Exemple #1
0
    def checkImage(self, callNo, refImageFileName):
        sys.stderr.write('Comparing snapshot from call %u against %s...\n' %
                         (callNo, refImageFileName))
        try:
            from PIL import Image
        except ImportError:
            sys.stderr.write(
                'warning: PIL not found, skipping image comparison\n')
            return

        srcImage = self.getImage(callNo)
        refImage = Image.open(refImageFileName)

        from snapdiff import Comparer
        comparer = Comparer(refImage, srcImage)
        precision = comparer.precision(filter=True)
        sys.stdout.write('precision of %f bits against %s\n' %
                         (precision, refImageFileName))
        if precision < self.threshold_precision:
            prefix = self.getNamePrefix()
            srcImageFileName = '%s.src.%u.png' % (prefix, callNo)
            diffImageFileName = '%s.diff.%u.png' % (prefix, callNo)
            srcImage.save(srcImageFileName)
            comparer.write_diff(diffImageFileName)
            fail('snapshot from call %u does not match %s' %
                 (callNo, refImageFileName))

        sys.stdout.flush()
        sys.stderr.write('\n')
    def checkImage(self, callNo, refImageFileName):
        sys.stderr.write('Comparing snapshot from call %u against %s...\n' % (callNo, refImageFileName))
        try:
            from PIL import Image
        except ImportError:
            sys.stderr.write('warning: PIL not found, skipping image comparison\n');
            return

        srcImage = self.getImage(callNo)
        refImage = Image.open(refImageFileName)

        from snapdiff import Comparer
        comparer = Comparer(refImage, srcImage)
        precision = comparer.precision(filter=True)
        sys.stdout.write('precision of %f bits against %s\n' % (precision, refImageFileName))
        if precision < self.threshold_precision:
            prefix = self.getNamePrefix()
            srcImageFileName = '%s.src.%u.png' % (prefix, callNo)
            diffImageFileName = '%s.diff.%u.png' % (prefix, callNo)
            srcImage.save(srcImageFileName)
            comparer.write_diff(diffImageFileName)
            fail('snapshot from call %u does not match %s' % (callNo, refImageFileName))

        sys.stdout.flush()
        sys.stderr.write('\n')
    def checkState(self, callNo, refStateFileName):
        sys.stderr.write('Comparing state dump from call %u against %s...\n' % (callNo, refStateFileName))

        srcState = self.getState(callNo)
        refState = self.getRefState(refStateFileName)

        from jsondiff import Comparer, Differ
        comparer = Comparer(ignore_added = True)
        match = comparer.visit(refState, srcState)
        if not match:
            prefix = self.getNamePrefix()
            srcStateFileName = '%s.src.%u.json' % (prefix, callNo)
            diffStateFileName = '%s.diff.%u.json' % (prefix, callNo)
            self.saveState(srcState, srcStateFileName)
            #diffStateFile = open(diffStateFileName, 'wt')
            diffStateFile = sys.stdout
            differ = Differ(diffStateFile, ignore_added = True)
            differ.visit(refState, srcState)
            fail('state from call %u does not match %s' % (callNo, refStateFileName))

        sys.stdout.flush()
        sys.stderr.write('\n')
Exemple #4
0
    def checkState(self, callNo, refStateFileName):
        sys.stderr.write('Comparing state dump from call %u against %s...\n' %
                         (callNo, refStateFileName))

        srcState = self.getState(callNo)
        refState = self.getRefState(refStateFileName)

        from jsondiff import Comparer, Differ
        comparer = Comparer(ignore_added=True)
        match = comparer.visit(refState, srcState)
        if not match:
            prefix = self.getNamePrefix()
            srcStateFileName = '%s.src.%u.json' % (prefix, callNo)
            diffStateFileName = '%s.diff.%u.json' % (prefix, callNo)
            self.saveState(srcState, srcStateFileName)
            #diffStateFile = open(diffStateFileName, 'wt')
            diffStateFile = sys.stdout
            differ = Differ(diffStateFile, ignore_added=True)
            differ.visit(refState, srcState)
            fail('state from call %u does not match %s' %
                 (callNo, refStateFileName))

        sys.stdout.flush()
        sys.stderr.write('\n')
Exemple #5
0
def main():
    '''Main program.
    '''

    global options

    # Parse command line options
    optparser = optparse.OptionParser(
        usage='\n\t%prog [options] -- [glretrace options] <trace>',
        version='%%prog')
    optparser.add_option(
        '-r', '--retrace', metavar='PROGRAM',
        type='string', dest='retrace', default='glretrace',
        help='retrace command [default: %default]')
    optparser.add_option(
        '--ref-env', metavar='NAME=VALUE',
        type='string', action='append', dest='ref_env', default=[],
        help='add variable to reference environment')
    optparser.add_option(
        '--src-env', metavar='NAME=VALUE',
        type='string', action='append', dest='src_env', default=[],
        help='add variable to source environment')
    optparser.add_option(
        '--diff-prefix', metavar='PATH',
        type='string', dest='diff_prefix', default='.',
        help='prefix for the difference images')
    optparser.add_option(
        '-t', '--threshold', metavar='BITS',
        type="float", dest="threshold", default=12.0,
        help="threshold precision  [default: %default]")
    optparser.add_option(
        '-S', '--snapshot-frequency', metavar='CALLSET',
        type="string", dest="snapshot_frequency", default='draw',
        help="calls to compare [default: %default]")
    optparser.add_option(
        '-o', '--output', metavar='FILE',
        type="string", dest="output",
        help="output file [default: stdout]")

    (options, args) = optparser.parse_args(sys.argv[1:])
    ref_env = parse_env(optparser, options.ref_env)
    src_env = parse_env(optparser, options.src_env)
    if not args:
        optparser.error("incorrect number of arguments")

    ref_setup = Setup(args, ref_env)
    src_setup = Setup(args, src_env)

    if options.output:
        output = open(options.output, 'wt')
    else:
        output = sys.stdout

    highligher = AutoHighlighter(output)

    highligher.write('call\tprecision\n')

    last_bad = -1
    last_good = 0
    ref_proc = ref_setup.retrace()
    try:
        src_proc = src_setup.retrace()
        try:
            while True:
                # Get the reference image
                ref_image, ref_comment = read_pnm(ref_proc.stdout)
                if ref_image is None:
                    break

                # Get the source image
                src_image, src_comment = read_pnm(src_proc.stdout)
                if src_image is None:
                    break

                assert ref_comment == src_comment

                call_no = int(ref_comment.strip())

                # Compare the two images
                comparer = Comparer(ref_image, src_image)
                precision = comparer.precision()

                mismatch = precision < options.threshold

                if mismatch:
                    highligher.color(highligher.red)
                    highligher.bold()
                highligher.write('%u\t%f\n' % (call_no, precision))
                if mismatch:
                    highligher.normal()

                if mismatch:
                    if options.diff_prefix:
                        prefix = os.path.join(options.diff_prefix, '%010u' % call_no)
                        prefix_dir = os.path.dirname(prefix)
                        if not os.path.isdir(prefix_dir):
                            os.makedirs(prefix_dir)
                        ref_image.save(prefix + '.ref.png')
                        src_image.save(prefix + '.src.png')
                        comparer.write_diff(prefix + '.diff.png')
                    if last_bad < last_good:
                        src_setup.diff_state(last_good, call_no, output)
                    last_bad = call_no
                else:
                    last_good = call_no

                highligher.flush()
        finally:
            src_proc.terminate()
    finally:
        ref_proc.terminate()
Exemple #6
0
def main():
    '''Main program.
    '''

    global options

    # Parse command line options
    optparser = optparse.OptionParser(
        usage='\n\t%prog [options] -- [glretrace options] <trace>',
        version='%%prog')
    optparser.add_option('-r',
                         '--retrace',
                         metavar='PROGRAM',
                         type='string',
                         dest='retrace',
                         default='glretrace',
                         help='retrace command [default: %default]')
    optparser.add_option('--ref-driver',
                         metavar='DRIVER',
                         type='string',
                         dest='ref_driver',
                         default=None,
                         help='force reference driver')
    optparser.add_option('--src-driver',
                         metavar='DRIVER',
                         type='string',
                         dest='src_driver',
                         default=None,
                         help='force source driver')
    optparser.add_option('--ref-arg',
                         metavar='OPTION',
                         type='string',
                         action='append',
                         dest='ref_args',
                         default=[],
                         help='pass argument to reference retrace')
    optparser.add_option('--src-arg',
                         metavar='OPTION',
                         type='string',
                         action='append',
                         dest='src_args',
                         default=[],
                         help='pass argument to source retrace')
    optparser.add_option('--ref-env',
                         metavar='NAME=VALUE',
                         type='string',
                         action='append',
                         dest='ref_env',
                         default=[],
                         help='add variable to reference environment')
    optparser.add_option('--src-env',
                         metavar='NAME=VALUE',
                         type='string',
                         action='append',
                         dest='src_env',
                         default=[],
                         help='add variable to source environment')
    optparser.add_option('--diff-prefix',
                         metavar='PATH',
                         type='string',
                         dest='diff_prefix',
                         default='.',
                         help='prefix for the difference images')
    optparser.add_option('-t',
                         '--threshold',
                         metavar='BITS',
                         type="float",
                         dest="threshold",
                         default=12.0,
                         help="threshold precision  [default: %default]")
    optparser.add_option('-S',
                         '--snapshot-frequency',
                         metavar='CALLSET',
                         type="string",
                         dest="snapshot_frequency",
                         default='draw',
                         help="calls to compare [default: %default]")
    optparser.add_option('--diff-state',
                         action='store_true',
                         dest='diff_state',
                         default=False,
                         help='diff state between failing calls')
    optparser.add_option('-o',
                         '--output',
                         metavar='FILE',
                         type="string",
                         dest="output",
                         help="output file [default: stdout]")

    (options, args) = optparser.parse_args(sys.argv[1:])
    ref_env = parse_env(optparser, options.ref_env)
    src_env = parse_env(optparser, options.src_env)
    if not args:
        optparser.error("incorrect number of arguments")

    if options.ref_driver:
        options.ref_args.insert(0, '--driver=' + options.ref_driver)
    if options.src_driver:
        options.src_args.insert(0, '--driver=' + options.src_driver)

    refRetracer = Retracer(options.retrace, options.ref_args + args, ref_env)
    srcRetracer = Retracer(options.retrace, options.src_args + args, src_env)

    if options.output:
        output = open(options.output, 'wt')
    else:
        output = sys.stdout

    highligher = AutoHighlighter(output)

    highligher.write('call\tprecision\n')

    last_bad = -1
    last_good = 0
    refRun = refRetracer.snapshot(options.snapshot_frequency)
    try:
        srcRun = srcRetracer.snapshot(options.snapshot_frequency)
        try:
            while True:
                # Get the reference image
                refImage, refCallNo = refRun.nextSnapshot()
                if refImage is None:
                    break

                # Get the source image
                srcImage, srcCallNo = srcRun.nextSnapshot()
                if srcImage is None:
                    break

                assert refCallNo == srcCallNo
                callNo = refCallNo

                # Compare the two images
                comparer = Comparer(refImage, srcImage)
                precision = comparer.precision()

                mismatch = precision < options.threshold

                if mismatch:
                    highligher.color(highligher.red)
                    highligher.bold()
                highligher.write('%u\t%f\n' % (callNo, precision))
                if mismatch:
                    highligher.normal()

                if mismatch:
                    if options.diff_prefix:
                        prefix = os.path.join(options.diff_prefix,
                                              '%010u' % callNo)
                        prefix_dir = os.path.dirname(prefix)
                        if not os.path.isdir(prefix_dir):
                            os.makedirs(prefix_dir)
                        refImage.save(prefix + '.ref.png')
                        srcImage.save(prefix + '.src.png')
                        comparer.write_diff(prefix + '.diff.png')
                    if last_bad < last_good and options.diff_state:
                        srcRetracer.diff_state(last_good, callNo, output)
                    last_bad = callNo
                else:
                    last_good = callNo

                highligher.flush()
        finally:
            srcRun.terminate()
    finally:
        refRun.terminate()
Exemple #7
0
def main():
    '''Main program.
    '''

    global options

    # Parse command line options
    optparser = optparse.OptionParser(
        usage='\n\t%prog [options] -- [glretrace options] <trace>',
        version='%%prog')
    optparser.add_option(
        '-r', '--retrace', metavar='PROGRAM',
        type='string', dest='retrace', default='glretrace',
        help='retrace command [default: %default]')
    optparser.add_option(
        '--ref-driver', metavar='DRIVER',
        type='string', dest='ref_driver', default=None,
        help='force reference driver')
    optparser.add_option(
        '--src-driver', metavar='DRIVER',
        type='string', dest='src_driver', default=None,
        help='force source driver')
    optparser.add_option(
        '--ref-arg', metavar='OPTION',
        type='string', action='append', dest='ref_args', default=[],
        help='pass argument to reference retrace')
    optparser.add_option(
        '--src-arg', metavar='OPTION',
        type='string', action='append', dest='src_args', default=[],
        help='pass argument to source retrace')
    optparser.add_option(
        '--ref-env', metavar='NAME=VALUE',
        type='string', action='append', dest='ref_env', default=[],
        help='add variable to reference environment')
    optparser.add_option(
        '--src-env', metavar='NAME=VALUE',
        type='string', action='append', dest='src_env', default=[],
        help='add variable to source environment')
    optparser.add_option(
        '--diff-prefix', metavar='PATH',
        type='string', dest='diff_prefix', default='.',
        help='prefix for the difference images')
    optparser.add_option(
        '-t', '--threshold', metavar='BITS',
        type="float", dest="threshold", default=12.0,
        help="threshold precision  [default: %default]")
    optparser.add_option(
        '-S', '--snapshot-frequency', metavar='CALLSET',
        type="string", dest="snapshot_frequency", default='draw',
        help="calls to compare [default: %default]")
    optparser.add_option(
        '--diff-state',
        action='store_true', dest='diff_state', default=False,
        help='diff state between failing calls')
    optparser.add_option(
        '-o', '--output', metavar='FILE',
        type="string", dest="output",
        help="output file [default: stdout]")

    (options, args) = optparser.parse_args(sys.argv[1:])
    ref_env = parse_env(optparser, options.ref_env)
    src_env = parse_env(optparser, options.src_env)
    if not args:
        optparser.error("incorrect number of arguments")
    
    if options.ref_driver:
        options.ref_args.insert(0, '--driver=' + options.ref_driver)
    if options.src_driver:
        options.src_args.insert(0, '--driver=' + options.src_driver)

    refRetracer = Retracer(options.retrace, options.ref_args + args, ref_env)
    srcRetracer = Retracer(options.retrace, options.src_args + args, src_env)

    if options.output:
        output = open(options.output, 'wt')
    else:
        output = sys.stdout

    highligher = AutoHighlighter(output)

    highligher.write('call\tprecision\n')

    last_bad = -1
    last_good = 0
    refRun = refRetracer.snapshot(options.snapshot_frequency)
    try:
        srcRun = srcRetracer.snapshot(options.snapshot_frequency)
        try:
            while True:
                # Get the reference image
                refImage, refCallNo = refRun.nextSnapshot()
                if refImage is None:
                    break

                # Get the source image
                srcImage, srcCallNo = srcRun.nextSnapshot()
                if srcImage is None:
                    break

                assert refCallNo == srcCallNo
                callNo = refCallNo

                # Compare the two images
                if isinstance(refImage, Image.Image) and isinstance(srcImage, Image.Image):
                    # Using PIL
                    numpyImages = False
                    comparer = Comparer(refImage, srcImage)
                    precision = comparer.precision()
                else:
                    # Using numpy (for floating point images)
                    # TODO: drop PIL when numpy path becomes general enough
                    import numpy
                    assert not isinstance(refImage, Image.Image)
                    assert not isinstance(srcImage, Image.Image)
                    numpyImages = True
                    assert refImage.shape == srcImage.shape
                    diffImage = numpy.square(srcImage - refImage)
                    match = numpy.all(diffImage == 0)
                    if match:
                        precision = 24
                    else:
                        precision = 0

                mismatch = precision < options.threshold

                if mismatch:
                    highligher.color(highligher.red)
                    highligher.bold()
                highligher.write('%u\t%f\n' % (callNo, precision))
                if mismatch:
                    highligher.normal()

                if mismatch:
                    if numpyImages:
                        dumpNumpyImage(output, refImage)
                        output.write("->\n")
                        dumpNumpyImage(output, srcImage)
                    if options.diff_prefix and not numpyImages:
                        prefix = os.path.join(options.diff_prefix, '%010u' % callNo)
                        prefix_dir = os.path.dirname(prefix)
                        if not os.path.isdir(prefix_dir):
                            os.makedirs(prefix_dir)
                        refImage.save(prefix + '.ref.png')
                        srcImage.save(prefix + '.src.png')
                        comparer.write_diff(prefix + '.diff.png')
                    if last_bad < last_good and options.diff_state:
                        srcRetracer.diff_state(last_good, callNo, output)
                    last_bad = callNo
                else:
                    last_good = callNo

                highligher.flush()
        finally:
            srcRun.terminate()
    finally:
        refRun.terminate()
Exemple #8
0
def main():
    '''Main program.
    '''

    global options

    # Parse command line options
    optparser = optparse.OptionParser(
        usage='\n\t%prog [options] -- [glretrace options] <trace>',
        version='%%prog')
    optparser.add_option('-r',
                         '--retrace',
                         metavar='PROGRAM',
                         type='string',
                         dest='retrace',
                         default='glretrace',
                         help='retrace command [default: %default]')
    optparser.add_option('--ref-env',
                         metavar='NAME=VALUE',
                         type='string',
                         action='append',
                         dest='ref_env',
                         default=[],
                         help='add variable to reference environment')
    optparser.add_option('--src-env',
                         metavar='NAME=VALUE',
                         type='string',
                         action='append',
                         dest='src_env',
                         default=[],
                         help='add variable to source environment')
    optparser.add_option('--diff-prefix',
                         metavar='PATH',
                         type='string',
                         dest='diff_prefix',
                         default='.',
                         help='prefix for the difference images')
    optparser.add_option('-t',
                         '--threshold',
                         metavar='BITS',
                         type="float",
                         dest="threshold",
                         default=12.0,
                         help="threshold precision  [default: %default]")
    optparser.add_option(
        '-S',
        '--snapshot-frequency',
        metavar='FREQUENCY',
        type="string",
        dest="snapshot_frequency",
        default='draw',
        help=
        "snapshot frequency: frame, framebuffer, or draw  [default: %default]")

    (options, args) = optparser.parse_args(sys.argv[1:])
    ref_env = parse_env(optparser, options.ref_env)
    src_env = parse_env(optparser, options.src_env)
    if not args:
        optparser.error("incorrect number of arguments")

    ref_setup = Setup(args, ref_env)
    src_setup = Setup(args, src_env)

    highligher = Highlighter(sys.stdout)

    highligher.write('call\tprecision\n')

    last_bad = -1
    last_good = 0
    ref_proc = ref_setup.retrace()
    try:
        src_proc = src_setup.retrace()
        try:
            while True:
                # Get the reference image
                ref_image, ref_comment = read_pnm(ref_proc.stdout)
                if ref_image is None:
                    break

                # Get the source image
                src_image, src_comment = read_pnm(src_proc.stdout)
                if src_image is None:
                    break

                assert ref_comment == src_comment

                call_no = int(ref_comment.strip())

                # Compare the two images
                comparer = Comparer(ref_image, src_image)
                precision = comparer.precision()

                mismatch = precision < options.threshold

                if mismatch:
                    highligher.color(highligher.red)
                    highligher.bold()
                highligher.write('%u\t%f\n' % (call_no, precision))
                if mismatch:
                    highligher.normal()

                if mismatch:
                    if options.diff_prefix:
                        prefix = os.path.join(options.diff_prefix,
                                              '%010u' % call_no)
                        prefix_dir = os.path.dirname(prefix)
                        if not os.path.isdir(prefix_dir):
                            os.makedirs(prefix_dir)
                        ref_image.save(prefix + '.ref.png')
                        src_image.save(prefix + '.src.png')
                        comparer.write_diff(prefix + '.diff.png')
                    if last_bad < last_good:
                        src_setup.diff_state(last_good, call_no)
                    last_bad = call_no
                else:
                    last_good = call_no

                highligher.flush()
        finally:
            src_proc.terminate()
    finally:
        ref_proc.terminate()
Exemple #9
0
def main():
    '''Main program.
    '''

    global options

    # Parse command line options
    optparser = optparse.OptionParser(
        usage='\n\t%prog [options] -- [glretrace options] <trace>',
        version='%%prog')
    optparser.add_option(
        '-r', '--retrace', metavar='PROGRAM',
        type='string', dest='retrace', default='glretrace',
        help='retrace command [default: %default]')
    optparser.add_option(
        '--ref-env', metavar='NAME=VALUE',
        type='string', action='append', dest='ref_env', default=[],
        help='reference environment variable')
    optparser.add_option(
        '--src-env', metavar='NAME=VALUE',
        type='string', action='append', dest='src_env', default=[],
        help='reference environment variable')
    optparser.add_option(
        '--diff-prefix', metavar='PATH',
        type='string', dest='diff_prefix', default='.',
        help='reference environment variable')
    optparser.add_option(
        '-t', '--threshold', metavar='BITS',
        type="float", dest="threshold", default=12.0,
        help="threshold precision  [default: %default]")
    optparser.add_option(
        '-S', '--snapshot-frequency', metavar='FREQUENCY',
        type="string", dest="snapshot_frequency", default='draw',
        help="snapshot frequency  [default: %default]")

    (options, args) = optparser.parse_args(sys.argv[1:])
    ref_env = parse_env(optparser, options.ref_env)
    src_env = parse_env(optparser, options.src_env)
    if not args:
        optparser.error("incorrect number of arguments")

    ref_setup = Setup(args, ref_env)
    src_setup = Setup(args, src_env)

    image_re = re.compile('^Wrote (.*\.png)$')

    last_good = -1
    last_bad = -1
    ref_snapshot_dir = tempfile.mkdtemp()
    try:
        src_snapshot_dir = tempfile.mkdtemp()
        try:
            ref_proc = ref_setup.retrace(ref_snapshot_dir)
            try:
                src_proc = src_setup.retrace(src_snapshot_dir)
                try:
                    for ref_line in ref_proc.stdout:
                        # Get the reference image
                        ref_line = ref_line.rstrip()
                        mo = image_re.match(ref_line)
                        if mo:
                            ref_image = mo.group(1)
                            for src_line in src_proc.stdout:
                                # Get the source image
                                src_line = src_line.rstrip()
                                mo = image_re.match(src_line)
                                if mo:
                                    src_image = mo.group(1)
                                    
                                    root, ext = os.path.splitext(os.path.basename(src_image))
                                    call_no = int(root)

                                    # Compare the two images
                                    comparer = Comparer(ref_image, src_image)
                                    precision = comparer.precision()

                                    sys.stdout.write('%u %f\n' % (call_no, precision))
                                    
                                    if precision < options.threshold:
                                        if options.diff_prefix:
                                            comparer.write_diff(os.path.join(options.diff_prefix, root + '.diff.png'))
                                        if last_bad < last_good:
                                            diff_state(src_setup, last_good, call_no)
                                        last_bad = call_no
                                    else:
                                        last_good = call_no

                                    sys.stdout.flush()
                                   
                                    os.unlink(src_image)
                                    break
                            os.unlink(ref_image)
                finally:
                    src_proc.terminate()
            finally:
                ref_proc.terminate()
        finally:
            shutil.rmtree(ref_snapshot_dir)
    finally:
        shutil.rmtree(src_snapshot_dir)
Exemple #10
0
def main():
    """Main program.
    """

    global options

    # Parse command line options
    optparser = optparse.OptionParser(usage="\n\t%prog [options] -- [glretrace options] <trace>", version="%%prog")
    optparser.add_option(
        "-r",
        "--retrace",
        metavar="PROGRAM",
        type="string",
        dest="retrace",
        default="glretrace",
        help="retrace command [default: %default]",
    )
    optparser.add_option(
        "--ref-driver", metavar="DRIVER", type="string", dest="ref_driver", default=None, help="force reference driver"
    )
    optparser.add_option(
        "--src-driver", metavar="DRIVER", type="string", dest="src_driver", default=None, help="force source driver"
    )
    optparser.add_option(
        "--ref-arg",
        metavar="OPTION",
        type="string",
        action="append",
        dest="ref_args",
        default=[],
        help="pass argument to reference retrace",
    )
    optparser.add_option(
        "--src-arg",
        metavar="OPTION",
        type="string",
        action="append",
        dest="src_args",
        default=[],
        help="pass argument to source retrace",
    )
    optparser.add_option(
        "--ref-env",
        metavar="NAME=VALUE",
        type="string",
        action="append",
        dest="ref_env",
        default=[],
        help="add variable to reference environment",
    )
    optparser.add_option(
        "--src-env",
        metavar="NAME=VALUE",
        type="string",
        action="append",
        dest="src_env",
        default=[],
        help="add variable to source environment",
    )
    optparser.add_option(
        "--diff-prefix",
        metavar="PATH",
        type="string",
        dest="diff_prefix",
        default=".",
        help="prefix for the difference images",
    )
    optparser.add_option(
        "-t",
        "--threshold",
        metavar="BITS",
        type="float",
        dest="threshold",
        default=12.0,
        help="threshold precision  [default: %default]",
    )
    optparser.add_option(
        "-S",
        "--snapshot-frequency",
        metavar="CALLSET",
        type="string",
        dest="snapshot_frequency",
        default="draw",
        help="calls to compare [default: %default]",
    )
    optparser.add_option(
        "-o", "--output", metavar="FILE", type="string", dest="output", help="output file [default: stdout]"
    )

    (options, args) = optparser.parse_args(sys.argv[1:])
    ref_env = parse_env(optparser, options.ref_env)
    src_env = parse_env(optparser, options.src_env)
    if not args:
        optparser.error("incorrect number of arguments")

    if options.ref_driver:
        options.ref_args.insert(0, "--driver=" + options.ref_driver)
    if options.src_driver:
        options.src_args.insert(0, "--driver=" + options.src_driver)

    ref_setup = Setup(options.ref_args + args, ref_env)
    src_setup = Setup(options.src_args + args, src_env)

    if options.output:
        output = open(options.output, "wt")
    else:
        output = sys.stdout

    highligher = AutoHighlighter(output)

    highligher.write("call\tprecision\n")

    last_bad = -1
    last_good = 0
    ref_proc = ref_setup.retrace()
    try:
        src_proc = src_setup.retrace()
        try:
            while True:
                # Get the reference image
                ref_image, ref_comment = read_pnm(ref_proc.stdout)
                if ref_image is None:
                    break

                # Get the source image
                src_image, src_comment = read_pnm(src_proc.stdout)
                if src_image is None:
                    break

                assert ref_comment == src_comment

                call_no = int(ref_comment.strip())

                # Compare the two images
                comparer = Comparer(ref_image, src_image)
                precision = comparer.precision()

                mismatch = precision < options.threshold

                if mismatch:
                    highligher.color(highligher.red)
                    highligher.bold()
                highligher.write("%u\t%f\n" % (call_no, precision))
                if mismatch:
                    highligher.normal()

                if mismatch:
                    if options.diff_prefix:
                        prefix = os.path.join(options.diff_prefix, "%010u" % call_no)
                        prefix_dir = os.path.dirname(prefix)
                        if not os.path.isdir(prefix_dir):
                            os.makedirs(prefix_dir)
                        ref_image.save(prefix + ".ref.png")
                        src_image.save(prefix + ".src.png")
                        comparer.write_diff(prefix + ".diff.png")
                    if last_bad < last_good:
                        src_setup.diff_state(last_good, call_no, output)
                    last_bad = call_no
                else:
                    last_good = call_no

                highligher.flush()
        finally:
            try:
                src_proc.terminate()
            except OSError:
                # Avoid http://bugs.python.org/issue14252
                pass
    finally:
        try:
            ref_proc.terminate()
        except OSError:
            # Avoid http://bugs.python.org/issue14252
            pass