Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 1 | # |
| 2 | # *********************************************************************** |
| 3 | # Warning: This file is auto-generated from main.py.in - edit it there. |
| 4 | # *********************************************************************** |
| 5 | # |
| 6 | # pybootchartgui is free software: you can redistribute it and/or modify |
| 7 | # it under the terms of the GNU General Public License as published by |
| 8 | # the Free Software Foundation, either version 3 of the License, or |
| 9 | # (at your option) any later version. |
| 10 | |
| 11 | # pybootchartgui is distributed in the hope that it will be useful, |
| 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | # GNU General Public License for more details. |
| 15 | |
| 16 | # You should have received a copy of the GNU General Public License |
| 17 | # along with pybootchartgui. If not, see <http://www.gnu.org/licenses/>. |
| 18 | |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 19 | import sys |
| 20 | import os |
| 21 | import optparse |
| 22 | |
| 23 | from . import parsing |
| 24 | from . import batch |
| 25 | |
| 26 | def _mk_options_parser(): |
| 27 | """Make an options parser.""" |
| 28 | usage = "%prog [options] /path/to/tmp/buildstats/<recipe-machine>/<BUILDNAME>/" |
| 29 | version = "%prog v1.0.0" |
| 30 | parser = optparse.OptionParser(usage, version=version) |
| 31 | parser.add_option("-i", "--interactive", action="store_true", dest="interactive", default=False, |
| 32 | help="start in active mode") |
| 33 | parser.add_option("-f", "--format", dest="format", default="png", choices=["png", "svg", "pdf"], |
| 34 | help="image format (png, svg, pdf); default format png") |
| 35 | parser.add_option("-o", "--output", dest="output", metavar="PATH", default=None, |
| 36 | help="output path (file or directory) where charts are stored") |
| 37 | parser.add_option("-s", "--split", dest="num", type=int, default=1, |
| 38 | help="split the output chart into <NUM> charts, only works with \"-o PATH\"") |
| 39 | parser.add_option("-m", "--mintime", dest="mintime", type=int, default=8, |
| 40 | help="only tasks longer than this time will be displayed") |
| 41 | parser.add_option("-M", "--minutes", action="store_true", dest="as_minutes", default=False, |
| 42 | help="display time in minutes instead of seconds") |
| 43 | # parser.add_option("-n", "--no-prune", action="store_false", dest="prune", default=True, |
| 44 | # help="do not prune the process tree") |
| 45 | parser.add_option("-q", "--quiet", action="store_true", dest="quiet", default=False, |
| 46 | help="suppress informational messages") |
| 47 | # parser.add_option("-t", "--boot-time", action="store_true", dest="boottime", default=False, |
| 48 | # help="only display the boot time of the boot in text format (stdout)") |
| 49 | parser.add_option("--very-quiet", action="store_true", dest="veryquiet", default=False, |
| 50 | help="suppress all messages except errors") |
| 51 | parser.add_option("--verbose", action="store_true", dest="verbose", default=False, |
| 52 | help="print all messages") |
| 53 | # parser.add_option("--profile", action="store_true", dest="profile", default=False, |
| 54 | # help="profile rendering of chart (only useful when in batch mode indicated by -f)") |
| 55 | # parser.add_option("--show-pid", action="store_true", dest="show_pid", default=False, |
| 56 | # help="show process ids in the bootchart as 'processname [pid]'") |
| 57 | parser.add_option("--show-all", action="store_true", dest="show_all", default=False, |
| 58 | help="show all processes in the chart") |
| 59 | # parser.add_option("--crop-after", dest="crop_after", metavar="PROCESS", default=None, |
| 60 | # help="crop chart when idle after PROCESS is started") |
| 61 | # parser.add_option("--annotate", action="append", dest="annotate", metavar="PROCESS", default=None, |
| 62 | # help="annotate position where PROCESS is started; can be specified multiple times. " + |
| 63 | # "To create a single annotation when any one of a set of processes is started, use commas to separate the names") |
| 64 | # parser.add_option("--annotate-file", dest="annotate_file", metavar="FILENAME", default=None, |
| 65 | # help="filename to write annotation points to") |
| 66 | parser.add_option("-T", "--full-time", action="store_true", dest="full_time", default=False, |
| 67 | help="display the full time regardless of which processes are currently shown") |
| 68 | return parser |
| 69 | |
| 70 | class Writer: |
| 71 | def __init__(self, write, options): |
| 72 | self.write = write |
| 73 | self.options = options |
| 74 | |
| 75 | def error(self, msg): |
| 76 | self.write(msg) |
| 77 | |
| 78 | def warn(self, msg): |
| 79 | if not self.options.quiet: |
| 80 | self.write(msg) |
| 81 | |
| 82 | def info(self, msg): |
| 83 | if self.options.verbose: |
| 84 | self.write(msg) |
| 85 | |
| 86 | def status(self, msg): |
| 87 | if not self.options.quiet: |
| 88 | self.write(msg) |
| 89 | |
| 90 | def _mk_writer(options): |
| 91 | def write(s): |
| 92 | print(s) |
| 93 | return Writer(write, options) |
| 94 | |
| 95 | def _get_filename(path): |
| 96 | """Construct a usable filename for outputs""" |
| 97 | dname = "." |
| 98 | fname = "bootchart" |
| 99 | if path != None: |
| 100 | if os.path.isdir(path): |
| 101 | dname = path |
| 102 | else: |
| 103 | fname = path |
| 104 | return os.path.join(dname, fname) |
| 105 | |
| 106 | def main(argv=None): |
| 107 | try: |
| 108 | if argv is None: |
| 109 | argv = sys.argv[1:] |
| 110 | |
| 111 | parser = _mk_options_parser() |
| 112 | options, args = parser.parse_args(argv) |
| 113 | |
| 114 | # Default values for disabled options |
| 115 | options.prune = True |
| 116 | options.boottime = False |
| 117 | options.profile = False |
| 118 | options.show_pid = False |
| 119 | options.crop_after = None |
| 120 | options.annotate = None |
| 121 | options.annotate_file = None |
| 122 | |
| 123 | writer = _mk_writer(options) |
| 124 | |
| 125 | if len(args) == 0: |
| 126 | print("No path given, trying /var/log/bootchart.tgz") |
| 127 | args = [ "/var/log/bootchart.tgz" ] |
| 128 | |
| 129 | res = parsing.Trace(writer, args, options) |
| 130 | |
| 131 | if options.interactive or options.output == None: |
| 132 | from . import gui |
| 133 | gui.show(res, options) |
| 134 | elif options.boottime: |
| 135 | import math |
| 136 | proc_tree = res.proc_tree |
| 137 | if proc_tree.idle: |
| 138 | duration = proc_tree.idle |
| 139 | else: |
| 140 | duration = proc_tree.duration |
| 141 | dur = duration / 100.0 |
| 142 | print('%02d:%05.2f' % (math.floor(dur/60), dur - 60 * math.floor(dur/60))) |
| 143 | else: |
| 144 | if options.annotate_file: |
| 145 | f = open (options.annotate_file, "w") |
| 146 | try: |
| 147 | for time in res[4]: |
| 148 | if time is not None: |
| 149 | # output as ms |
Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 150 | f.write(time * 10) |
Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 151 | finally: |
| 152 | f.close() |
| 153 | filename = _get_filename(options.output) |
| 154 | res_list = parsing.split_res(res, options) |
| 155 | n = 1 |
| 156 | width = len(str(len(res_list))) |
| 157 | s = "_%%0%dd." % width |
| 158 | for r in res_list: |
| 159 | if len(res_list) == 1: |
| 160 | f = filename + "." + options.format |
| 161 | else: |
| 162 | f = filename + s % n + options.format |
| 163 | n = n + 1 |
| 164 | def render(): |
| 165 | batch.render(writer, r, options, f) |
| 166 | if options.profile: |
| 167 | import cProfile |
| 168 | import pstats |
| 169 | profile = '%s.prof' % os.path.splitext(filename)[0] |
| 170 | cProfile.runctx('render()', globals(), locals(), profile) |
| 171 | p = pstats.Stats(profile) |
| 172 | p.strip_dirs().sort_stats('time').print_stats(20) |
| 173 | else: |
| 174 | render() |
| 175 | |
| 176 | return 0 |
| 177 | except parsing.ParseError as ex: |
| 178 | print(("Parse error: %s" % ex)) |
| 179 | return 2 |
| 180 | |
| 181 | |
| 182 | if __name__ == '__main__': |
| 183 | sys.exit(main()) |