| #! /usr/bin/python |
| # -*- python -*- |
| # -*- coding: utf-8 -*- |
| # tuna - Application Tuning GUI |
| # Copyright (C) 2009 Arnaldo Carvalho de Melo |
| # Arnaldo Carvalho de Melo <acme@redhat.com> |
| # |
| # 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) |