If you want to try my script, or even improve it (probably not hard!), it's
attached.

You can run it by first collecting a log of timestamps, which I did with a
clean build:

scons --debug=action-timestamps -j48 build/ARM/gem5.opt | tee log.txt

and then run the script:

./scons_timeline.py log.txt

I would be curious how that looks on our big compile test machine!

Gabe

On Mon, Oct 18, 2021 at 10:20 PM Gabe Black <[email protected]> wrote:

> Wow, now I remember why I don't like GUI programming :-/
>
> Well, I sort of got some results, and the upshot is that linking gem5
> takes a long time :-P. And I am able to at least superficially have 48
> things going during the build, although it is not necessarily 48 times
> faster than doing things one at a time.
>
> Gabe
>
> On Mon, Oct 18, 2021 at 5:45 PM Gabe Black <[email protected]> wrote:
>
>> Hey folks, a while ago some students developed a GUI tool for gem5. While
>> I think that was great and really hasn't gotten the attention (or
>> adoption?) that a tool like that should, I was looking for it for a more
>> practical reason but haven't been able to find it.
>>
>> Does anybody know where it ended up? And additionally/alternatively, does
>> anybody know what guil toolkit that used? I want to write up a quick SCons
>> build performance visualizer and (assuming it goes into util?) I wouldn't
>> want to add a second gui toolkit dependency.
>>
>> Thanks!
>> Gabe
>>
>
#! /usr/bin/env python3
#
# Copyright 2021 Google, Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import argparse
import collections
import re
import wx
import wx.lib.plot

parser = argparse.ArgumentParser(
        description='Visualize SCons action timestamps')
parser.add_argument('log_file',
    help="file with SCon's log output when run with --debug-action-timestamps")

args = parser.parse_args()

class Bound:
    def __init__(self, target, name, value):
        self.target = target
        self.is_start = (name == 'start')
        self.value = float(value)

class Target:
    def __init__(self):
        self.name = None
        self._start = None
        self._end = None

    @property
    def start(self):
        assert(self._start is not None)
        return self._start

    @property
    def end(self):
        assert(self._end is not None)
        return self._end

    @start.setter
    def start(self, bound):
        assert(self._start is None)
        self._start = bound

    @end.setter
    def end(self, bound):
        assert(self._end is None)
        self._end = bound

targets = collections.defaultdict(Target)

timestamp_re = re.compile(r'Command execution (?P<ttype>start|end) '
                          r'timestamp: (?P<name>[^:]*): '
                          r'(?P<seconds>[\d\.]*)')

skipped = 0
with open(args.log_file) as log:
    lines = log.readlines()
    for line in lines:
        match = timestamp_re.match(line)
        if not match:
            skipped = skipped + 1
            continue
        name = match.group('name')
        target = targets[name]
        target.name = name
        bound = Bound(target, match.group('ttype'), match.group('seconds'))
        if bound.is_start:
            target.start = bound
        else:
            target.end = bound

# Find the bounds for the times for all the targets.

min_start = min(target.start.value for target in targets.values())
max_end = max(target.end.value for target in targets.values())

bounds = []
for target in targets.values():
    bounds.extend([target.start, target.end])

bounds = sorted(bounds, key=lambda b: b.value)

class Timeline(wx.Frame):
    def __init__(self):
        super(Timeline, self).__init__(None, title='SCons timeline')

        panel = wx.Panel(self)

        in_progress = list()
        available_idx = list()

        self.canvas = wx.lib.plot.PlotCanvas(panel)

        bars = []

        for bound in bounds:
            if bound.is_start:
                target = bound.target
                start = target.start
                end = target.end

                if not available_idx:
                    idx = len(in_progress)
                    in_progress.append(target)
                else:
                    idx = available_idx.pop()
                    in_progress[idx] = target

                bars.append(wx.lib.plot.PolyLine(
                    [(start.value - min_start, idx + 1),
                     (end.value - min_start, idx + 1)],
                    colour="orange", width=10))
            else:
                idx = in_progress.index(bound.target)
                in_progress[idx] = None
                available_idx.append(idx)

        print(f"I have {len(bars)} bars!")
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.canvas, 1, wx.EXPAND | wx.ALL, 10)
        panel.SetSizer(sizer)

        graphics = wx.lib.plot.PlotGraphics(bars, "SCons timeline",
                "seconds", "job")
        self.canvas.Draw(graphics)
        self.canvas.showScrollbars = True
        self.canvas.enableZoom = True

app = wx.App()

timeline = Timeline()
timeline.Show()

app.MainLoop()
_______________________________________________
gem5-dev mailing list -- [email protected]
To unsubscribe send an email to [email protected]
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to