aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/msgfmt.py203
-rwxr-xr-xtools/profiler/report145
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()
+