diff options
author | astokes <astokes@ef72aa8b-4018-0410-8976-d6e080ef94d8> | 2010-02-17 16:28:17 +0000 |
---|---|---|
committer | astokes <astokes@ef72aa8b-4018-0410-8976-d6e080ef94d8> | 2010-02-17 16:28:17 +0000 |
commit | 18191c43943661b2d61b191ea95a9c9351bd465c (patch) | |
tree | dd426874c830ec029dbd44eec4e469131d4fadc9 /tools | |
parent | 494f1de1db6c29a3f5f6d0e5cabc29b86eaf99e8 (diff) | |
download | sos-18191c43943661b2d61b191ea95a9c9351bd465c.tar.gz |
- moved 1.9 to trunkr1.9
git-svn-id: svn+ssh://svn.fedorahosted.org/svn/sos/trunk@778 ef72aa8b-4018-0410-8976-d6e080ef94d8
Diffstat (limited to 'tools')
-rw-r--r-- | tools/msgfmt.py | 203 | ||||
-rwxr-xr-x | tools/profiler/report | 145 |
2 files changed, 348 insertions, 0 deletions
diff --git a/tools/msgfmt.py b/tools/msgfmt.py new file mode 100644 index 00000000..8a2d4e66 --- /dev/null +++ b/tools/msgfmt.py @@ -0,0 +1,203 @@ +#! /usr/bin/env python +# -*- coding: iso-8859-1 -*- +# Written by Martin v. Löwis <loewis@informatik.hu-berlin.de> + +"""Generate binary message catalog from textual translation description. + +This program converts a textual Uniforum-style message catalog (.po file) into +a binary GNU catalog (.mo file). This is essentially the same function as the +GNU msgfmt program, however, it is a simpler implementation. + +Usage: msgfmt.py [OPTIONS] filename.po + +Options: + -o file + --output-file=file + Specify the output file to write to. If omitted, output will go to a + file named filename.mo (based off the input file name). + + -h + --help + Print this message and exit. + + -V + --version + Display version information and exit. +""" + +import sys +import os +import getopt +import struct +import array + +__version__ = "1.1" + +MESSAGES = {} + + + +def usage(code, msg=''): + print >> sys.stderr, __doc__ + if msg: + print >> sys.stderr, msg + sys.exit(code) + + + +def add(id, str, fuzzy): + "Add a non-fuzzy translation to the dictionary." + global MESSAGES + if not fuzzy and str: + MESSAGES[id] = str + + + +def generate(): + "Return the generated output." + global MESSAGES + keys = MESSAGES.keys() + # the keys are sorted in the .mo file + keys.sort() + offsets = [] + ids = strs = '' + for id in keys: + # For each string, we need size and file offset. Each string is NUL + # terminated; the NUL does not count into the size. + offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id]))) + ids += id + '\0' + strs += MESSAGES[id] + '\0' + output = '' + # The header is 7 32-bit unsigned integers. We don't use hash tables, so + # the keys start right after the index tables. + # translated string. + keystart = 7*4+16*len(keys) + # and the values start after the keys + valuestart = keystart + len(ids) + koffsets = [] + voffsets = [] + # The string table first has the list of keys, then the list of values. + # Each entry has first the size of the string, then the file offset. + for o1, l1, o2, l2 in offsets: + koffsets += [l1, o1+keystart] + voffsets += [l2, o2+valuestart] + offsets = koffsets + voffsets + output = struct.pack("Iiiiiii", + 0x950412deL, # Magic + 0, # Version + len(keys), # # of entries + 7*4, # start of key index + 7*4+len(keys)*8, # start of value index + 0, 0) # size and offset of hash table + output += array.array("i", offsets).tostring() + output += ids + output += strs + return output + + + +def make(filename, outfile): + ID = 1 + STR = 2 + + # Compute .mo name from .po name and arguments + if filename.endswith('.po'): + infile = filename + else: + infile = filename + '.po' + if outfile is None: + outfile = os.path.splitext(infile)[0] + '.mo' + + try: + lines = open(infile).readlines() + except IOError, msg: + print >> sys.stderr, msg + sys.exit(1) + + section = None + fuzzy = 0 + + # Parse the catalog + lno = 0 + for l in lines: + lno += 1 + # If we get a comment line after a msgstr, this is a new entry + if l[0] == '#' and section == STR: + add(msgid, msgstr, fuzzy) + section = None + fuzzy = 0 + # Record a fuzzy mark + if l[:2] == '#,' and l.find('fuzzy'): + fuzzy = 1 + # Skip comments + if l[0] == '#': + continue + # Now we are in a msgid section, output previous section + if l.startswith('msgid'): + if section == STR: + add(msgid, msgstr, fuzzy) + section = ID + l = l[5:] + msgid = msgstr = '' + # Now we are in a msgstr section + elif l.startswith('msgstr'): + section = STR + l = l[6:] + # Skip empty lines + l = l.strip() + if not l: + continue + # XXX: Does this always follow Python escape semantics? + l = eval(l) + if section == ID: + msgid += l + elif section == STR: + msgstr += l + else: + print >> sys.stderr, 'Syntax error on %s:%d' % (infile, lno), \ + 'before:' + print >> sys.stderr, l + sys.exit(1) + # Add last entry + if section == STR: + add(msgid, msgstr, fuzzy) + + # Compute output + output = generate() + + try: + open(outfile,"wb").write(output) + except IOError,msg: + print >> sys.stderr, msg + + + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], 'hVo:', + ['help', 'version', 'output-file=']) + except getopt.error, msg: + usage(1, msg) + + outfile = None + # parse options + for opt, arg in opts: + if opt in ('-h', '--help'): + usage(0) + elif opt in ('-V', '--version'): + print >> sys.stderr, "msgfmt.py", __version__ + sys.exit(0) + elif opt in ('-o', '--output-file'): + outfile = arg + # do it + if not args: + print >> sys.stderr, 'No input file given' + print >> sys.stderr, "Try `msgfmt --help' for more information." + return + + for filename in args: + make(filename, outfile) + + +if __name__ == '__main__': + main() diff --git a/tools/profiler/report b/tools/profiler/report new file mode 100755 index 00000000..13577fcc --- /dev/null +++ b/tools/profiler/report @@ -0,0 +1,145 @@ +#!/usr/bin/python + +# profile reporter + +import sys, os, operator, string +from optparse import OptionParser +from glob import glob +from subprocess import Popen, PIPE +import tarfile + +class GlobalVars: + def __init__(self): + pass + +class MyWriter: + def __init__(self, stdout, filename): + self.stdout = stdout + self.logfile = file(filename, 'w') + + def write(self, text): + self.stdout.write(text) + self.logfile.write(text) + + def close(self): + self.stdout.close() + self.logfile.close() + +def parse_options(opts): + """ parse cmd line opts """ + + parser = OptionParser() + parser.add_option("-f","--filename", dest="filename", + help="write report to FILENAME") + parser.add_option("-t", "--time", dest="rtime", + help="set minimum RUNTIME to report", action="store", + default=float(0.1), type="float") + parser.add_option("-i", "--input", dest="rpt_dir", + help="define directory of sosreport archives", + action="store", default=False) + + GlobalVars.cmdlineopts, GlobalVars.cmdlineargs = parser.parse_args(opts) + + if not GlobalVars.cmdlineopts.rpt_dir: + raise SystemExit("\nPlease make sure to specify --input FILES\n") + +def uncompress_reports(fname): + """ uncompresses the sosreport """ + p = Popen(["xz","-d", fname], stdout=PIPE, stdin=PIPE) + out, err = p.communicate() + if err: + print "Problem extracting %s" % (fname,) + return + +def read_archive(fname): + """ reads tarfile archive and grabs the sosprofile.log fileobj """ + tar = tarfile.open(os.path.abspath(fname), "r:") + for tarinfo in tar.getmembers(): + if 'sosprofile.log' in tarinfo.name: + fobj = tar.extractfile(tarinfo) + buf = fobj.read() + tar.close() + return buf + +def timeoutput(secs): + if secs > 60: + secs = round(secs) / 60 + return (secs, 'm') + elif secs < 60: + return (secs, 's') + +def sort_profile(): + """ provide reports on sosreport profiling """ + # uncompress reports from input files + for rpt in glob(GlobalVars.cmdlineopts.rpt_dir+"/*.xz"): + uncompress_reports(os.path.abspath(rpt)) + GlobalVars.rpt_count = 0 + GlobalVars.timecount = 0 + GlobalVars.lrc = {} + for rpt in glob(GlobalVars.cmdlineopts.rpt_dir+"/*.tar"): + buf = read_archive(rpt) + time_sorts=[] + if not buf: + continue + for line in buf.split("\n"): + try: + cmd, rtime = line.split("time:") + try: + # cmds that span multiple lines still need time calculated + cmd = cmd.split(":")[1] + except IndexError: + cmd, rtime = line.split("time:") + time_sorts.append((cmd.strip(), rtime.strip())) + except ValueError: + continue + time_count = 0 + b_val_count = 0 + write_stats = open(rpt + ".profile_report", 'w') + write_stats.write(28 * ' ' + 'SOSreport Profile Report' + 27 * ' ' + "\n") + write_stats.write(79 * '.' + "\n") + for a,b in sorted(time_sorts, key=operator.itemgetter(1)): + b_val = float(b) + time_count += b_val + if b_val > float(GlobalVars.cmdlineopts.rtime): + b_val_count += b_val + write_stats.write("%-79s %s\n" % (a[:78], b)) + if GlobalVars.lrc.has_key(a) and \ + GlobalVars.lrc[a] < b_val: + GlobalVars.lrc[a] = b_val + else: + GlobalVars.lrc[a] = b_val + # Keep up with total run time for all reports + GlobalVars.timecount += time_count + # Write out totals per report + write_stats.write(79 * '.' + "\n") + write_stats.write("Totals:\n") + secs, fmt = timeoutput(b_val_count) + write_stats.write("cumulative > %s: \t%f%s\n" % (GlobalVars.cmdlineopts.rtime, secs, fmt)) + secs, fmt = timeoutput(time_count) + write_stats.write("cumulative total:\t%f%s\n" % (secs,fmt)) + write_stats.close() + # increment report count so we can get an average runtime + GlobalVars.rpt_count += 1 + +if __name__ == "__main__": + parse_options(sys.argv[1:]) + if GlobalVars.cmdlineopts.filename: + writer = MyWriter(sys.stdout, GlobalVars.cmdlineopts.filename) + sys.stdout = writer + print "Building reports ..." + sort_profile() + print 79 * "-" + print "Total runtime for %d reports is %fs" % (round(GlobalVars.rpt_count, 2), GlobalVars.timecount) + print "Average total runtime of %d reports is %fs" % (round(GlobalVars.rpt_count, 2), GlobalVars.timecount / GlobalVars.rpt_count) + print 79 * "-" + print + print "Longest running commands > %s:" % (GlobalVars.cmdlineopts.rtime,) + print 79 * "-" + for cmd, rtime in sorted(GlobalVars.lrc.iteritems(), key=operator.itemgetter(1)): + print "%-75s %s" % (cmd[:69], rtime) + + if GlobalVars.cmdlineopts.filename: + print 79 * "-" + print "Report log written to: %s" % (GlobalVars.cmdlineopts.filename,) + writer.close() + |