#! /usr/bin/python # -*- python -*- # -*- coding: utf-8 -*- # tuna - Application Tuning GUI # Copyright (C) 2009 Arnaldo Carvalho de Melo # Arnaldo Carvalho de Melo # # This application 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; version 2. # # This application 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. import filecmp, getopt, os, posix, signal, sys, tempfile regtest_output_dir = "/media/tb/pahole/regtest/" regtest_obj_dir = "/media/tb/debuginfo/usr/lib/debug/" tools = {"pahole": { "dwarf": "--flat_arrays --show_private_classes --fixup_silly_bitfields --first_obj_only --classes_as_structs" }} all_formats = ("ctf", "dwarf") formats = all_formats len_debug_dir = len(regtest_obj_dir) verbose = 1 # Turn this on when testing CTF generated files use_options = False def diff_file(from_filename, to_filename): fd, diff_filename = tempfile.mkstemp() command = 'diff -up "%s" "%s" > %s' % (from_filename, to_filename, diff_filename) if verbose > 1: print command try: os.system(command) os.system("vim %s" % diff_filename) finally: os.unlink(diff_filename) def dir_has_no_diffs(dirname): return os.access(os.path.join(dirname, ".no_diffs"), os.F_OK) def set_dir_has_no_diffs(dirname): f = file(os.path.join(dirname, ".no_diffs"), "w") f.close() def reset_dir_has_no_diffs(dirname): os.unlink(os.path.join(dirname, ".no_diffs")) def diff_dir(from_dir, to_dir, dir = None, recursive = True): if dir: from_dir = os.path.join(from_dir, dir) to_dir = os.path.join(to_dir, dir) print "\r%-130s" % from_dir sys.stdout.flush() diff = filecmp.dircmp(from_dir, to_dir) if not dir_has_no_diffs(to_dir): diff_files = diff.diff_files if diff_files: diff_files.sort() print "\n %s" % from_dir sys.stdout.flush() for f in diff_files: diff_file(os.path.join(from_dir, f), os.path.join(to_dir, f)) else: set_dir_has_no_diffs(to_dir) if not recursive: return common_dirs = diff.common_dirs if not common_dirs: return common_dirs.sort() for dir in common_dirs: diff_dir(from_dir, to_dir, dir) def do_diff_dwarfs2ctfs(): diff_dir(os.path.join(regtest_output_dir, "after", "pahole", "dwarf"), os.path.join(regtest_output_dir, "after", "pahole", "ctf")) def do_diff_dwarfs(): diff_dir(os.path.join(regtest_output_dir, "before", "pahole", "dwarf"), os.path.join(regtest_output_dir, "after", "pahole", "dwarf")) def do_tool(tool, before_after, format, dirname, fname, prepend_obj_dir = False): if prepend_obj_dir: fname += ".debug" fixed_dirname = dirname else: fixed_dirname = dirname[len_debug_dir:] tool_output_dir = os.path.join(regtest_output_dir, before_after, tool, format, fixed_dirname) obj_path = os.path.join(dirname, fname) if prepend_obj_dir: obj_path = os.path.join(regtest_obj_dir, obj_path) if os.path.islink(obj_path) or os.path.isdir(obj_path): return try: os.makedirs(tool_output_dir) except: pass if dir_has_no_diffs(tool_output_dir): reset_dir_has_no_diffs(tool_output_dir) output_file = os.path.join(tool_output_dir, fname[:-6]) if use_options and tools[tool].has_key(format): options = tools[tool][format] else: options = "" command = '%s -F %s %s %s > "%s"' % (tool, format, options, obj_path, output_file) if verbose > 1: print command sys.stdout.flush() elif verbose > 0: print "%s: %s" % (format, os.path.join(fixed_dirname, fname[:-6])) os.system(command) def do_tool_on_files(arg, dirname, fnames, prepend_obj_dir = False): if dirname.find("/.") >= 0: return tool, before_after = arg for fname in fnames: if not prepend_obj_dir and fname[-6:] != ".debug": continue for format in formats: do_tool(tool, before_after, format, dirname, fname, prepend_obj_dir) def do_tools(before_after): for tool in tools.keys(): os.path.walk(regtest_obj_dir, do_tool_on_files, (tool, before_after)) def do_ctf(dirname, fname, prepend_obj_dir = False): if prepend_obj_dir: fname += ".debug" fixed_dirname = dirname else: fixed_dirname = dirname[len_debug_dir:] obj_path = os.path.join(dirname, fname) if prepend_obj_dir: obj_path = os.path.join(regtest_obj_dir, obj_path) if os.path.islink(obj_path) or os.path.isdir(obj_path): return command = 'pahole -Z "%s" 2> /dev/null' % obj_path if verbose > 1: print command elif verbose > 0: print os.path.join(fixed_dirname, fname[:-6]) os.system(command) def do_ctf_on_files(arg, dirname, fnames, prepend_obj_dir = False): if dirname.find("/.") >= 0: return for fname in fnames: if not prepend_obj_dir and fname[-6:] != ".debug": continue do_ctf(dirname, fname, prepend_obj_dir) def do_ctfs(): os.path.walk(regtest_obj_dir, do_ctf_on_files, None) def sig_exit(sig_number, stack_frame): sys.exit(1) def listdebugs(dirname): fnames = [] for fname in os.listdir(os.path.join(regtest_obj_dir, dirname)): if fname[-6:] != ".debug": continue obj_path = os.path.join(regtest_obj_dir, dirname, fname) if os.path.islink(obj_path) or os.path.isdir(obj_path): continue fnames.append(fname[:-6]) return fnames def usage(): print 'Usage: regtest [OPTIONS]' fmt = '\t%-20s %s' print fmt % ('-h, --help', 'Give this help list') print fmt % ('-a, --after', 'Generate new output') print fmt % ('-b, --before', 'Generate old output') print fmt % ('-c, --ctf_diff', 'Diff between DWARF and CTF for new output') print fmt % ('-C, --ctf_encode', 'Encode CTF into object files') print fmt % ('-d, --diff', 'Diff between old and new output') print fmt % ('-f, --formats', 'formats used (default: %s)' ','.join(formats)) def main(argv): global formats for sig in (signal.SIGHUP, signal.SIGINT, signal.SIGTERM): signal.signal(sig, sig_exit) try: short = "habcCdf:" long = ("help", "after", "before", "ctf_diff", "ctf_encode", "diff", "formats") opts, args = getopt.getopt(sys.argv[1:], short, long) except getopt.GetoptError, err: usage() print str(err) sys.exit(2) for o, a in opts: if o in ("-h", "--help"): usage() return elif o in ("-f", "--formats"): formats = a.split(',') elif o in ("-a", "--after", "-b", "--before", "-c", "--ctf_diff", "-C", "--ctf_encode", "-d", "--diff"): if len(args) > 0: dirname = args[0] if len(args) > 1: fnames = args[1:] elif o in ('-a', '--after', '-b', '--before', '-C', '--ctf_encode'): fnames = listdebugs(dirname) if o in ('-b', '--before', '-a', '--after'): if o in ('-b', '--before'): when = 'before' else: when = 'after' if len(args) > 0: for tool in tools.keys(): arg = (tool, when) do_tool_on_files(arg, dirname, fnames, True) else: do_tools(when) elif o in ('-d', '--diff'): if len(args) > 0: from_dir = os.path.join(regtest_output_dir, "before", "pahole", "dwarf", dirname) to_dir = os.path.join(regtest_output_dir, "after", "pahole", "dwarf", dirname) if len(args) > 1: for fname in fnames: diff_file(os.path.join(from_dir, fname), os.path.join(to_dir, fname)) else: diff_dir(from_dir, to_dir, recursive = False) else: do_diff_dwarfs() elif o in ('-C', 'ctf'): if len(args) > 0: do_ctf_on_files(None, dirname, fnames, True) else: do_ctfs() elif o in ('-c', 'ctf_diff'): if len(args) > 0: from_dir = os.path.join(regtest_output_dir, "after", "pahole", "dwarf", dirname) to_dir = os.path.join(regtest_output_dir, "after", "pahole", "ctf", dirname) if len(args) > 1: for fname in fnames: diff_file(os.path.join(from_dir, fname), os.path.join(to_dir, fname)) else: diff_dir(from_dir, to_dir, recursive = False) else: do_diff_dwarfs2ctfs() if __name__ == '__main__': main(sys.argv)