dram_lat_mem_rd_plot.py revision 13540
12SN/A#!/usr/bin/env python2.7
21762SN/A
32SN/A# Copyright (c) 2015 ARM Limited
42SN/A# All rights reserved
52SN/A#
62SN/A# The license below extends only to copyright in the software and shall
72SN/A# not be construed as granting a license to any other intellectual
82SN/A# property including but not limited to intellectual property relating
92SN/A# to a hardware implementation of the functionality of the software
102SN/A# licensed hereunder.  You may use the software subject to the license
112SN/A# terms below provided that you ensure that this notice is replicated
122SN/A# unmodified and in its entirety in all distributions of the software,
132SN/A# modified or unmodified, in source code or in binary form.
142SN/A#
152SN/A# Redistribution and use in source and binary forms, with or without
162SN/A# modification, are permitted provided that the following conditions are
172SN/A# met: redistributions of source code must retain the above copyright
182SN/A# notice, this list of conditions and the following disclaimer;
192SN/A# redistributions in binary form must reproduce the above copyright
202SN/A# notice, this list of conditions and the following disclaimer in the
212SN/A# documentation and/or other materials provided with the distribution;
222SN/A# neither the name of the copyright holders nor the names of its
232SN/A# contributors may be used to endorse or promote products derived from
242SN/A# this software without specific prior written permission.
252SN/A#
262SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
272665Ssaidi@eecs.umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
282665Ssaidi@eecs.umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
292665Ssaidi@eecs.umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
302665Ssaidi@eecs.umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
312SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
322SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
332SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
342SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
352SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
362SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
372SN/A#
3856SN/A# Authors: Andreas Hansson
3956SN/A
401158SN/Atry:
41146SN/A    import matplotlib.pyplot as plt
421858SN/A    import matplotlib as mpl
432680Sktlim@umich.edu    import numpy as np
442378SN/Aexcept ImportError:
452522SN/A    print "Failed to import matplotlib and numpy"
462401SN/A    exit(-1)
47146SN/A
48360SN/Aimport sys
49695SN/Aimport re
502093SN/A
512378SN/A# This script is intended to post process and plot the output from
522SN/A# running configs/dram/lat_mem_rd.py, as such it parses the simout and
532715Sstever@eecs.umich.edu# stats.txt to get the relevant data points.
542715Sstever@eecs.umich.edudef main():
552715Sstever@eecs.umich.edu
562715Sstever@eecs.umich.edu    if len(sys.argv) != 2:
572715Sstever@eecs.umich.edu        print "Usage: ", sys.argv[0], "<simout directory>"
582715Sstever@eecs.umich.edu        exit(-1)
592715Sstever@eecs.umich.edu
602715Sstever@eecs.umich.edu    try:
612715Sstever@eecs.umich.edu        stats = open(sys.argv[1] + '/stats.txt', 'r')
622715Sstever@eecs.umich.edu    except IOError:
632715Sstever@eecs.umich.edu        print "Failed to open ", sys.argv[1] + '/stats.txt', " for reading"
642715Sstever@eecs.umich.edu        exit(-1)
652715Sstever@eecs.umich.edu
662715Sstever@eecs.umich.edu    try:
672SN/A        simout = open(sys.argv[1] + '/simout', 'r')
682107SN/A    except IOError:
692SN/A        print "Failed to open ", sys.argv[1] + '/simout', " for reading"
702SN/A        exit(-1)
712SN/A
722SN/A    # Get the address ranges
732SN/A    got_ranges = False
742SN/A    ranges = []
751858SN/A
76360SN/A    iterations = 1
772SN/A
782SN/A    for line in simout:
792SN/A        if got_ranges:
802SN/A            ranges.append(int(line) / 1024)
812SN/A
821450SN/A        match = re.match("lat_mem_rd with (\d+) iterations, ranges:.*", line)
832378SN/A        if match:
842SN/A            got_ranges = True
852SN/A            iterations = int(match.groups(0)[0])
862SN/A
872378SN/A    simout.close()
882SN/A
892SN/A    if not got_ranges:
902SN/A        print "Failed to get address ranges, ensure simout is up-to-date"
912SN/A        exit(-1)
922SN/A
932SN/A    # Now parse the stats
942SN/A    raw_rd_lat = []
952SN/A
962SN/A    for line in stats:
972SN/A        match = re.match(".*readLatencyHist::mean\s+(.+)\s+#.*", line)
982SN/A        if match:
991450SN/A            raw_rd_lat.append(float(match.groups(0)[0]) / 1000)
1001514SN/A    stats.close()
1012378SN/A
1022SN/A    # The stats also contain the warming, so filter the latency stats
1032SN/A    i = 0
1042SN/A    filtered_rd_lat = []
1052378SN/A    for l in raw_rd_lat:
1062SN/A        if i % (iterations + 1) == 0:
1072SN/A            pass
1082SN/A        else:
109729SN/A            filtered_rd_lat.append(l)
1102SN/A        i = i + 1
1112SN/A
1122SN/A    # Next we need to take care of the iterations
1132SN/A    rd_lat = []
1142SN/A    for i in range(iterations):
1152SN/A        rd_lat.append(filtered_rd_lat[i::iterations])
1162SN/A
1172SN/A    final_rd_lat = map(lambda p: min(p), zip(*rd_lat))
1182SN/A
1192SN/A    # Sanity check
1202SN/A    if not (len(ranges) == len(final_rd_lat)):
1212SN/A        print "Address ranges (%d) and read latency (%d) do not match" % \
1222SN/A            (len(ranges), len(final_rd_lat))
1232SN/A        exit(-1)
1242SN/A
1252SN/A    for (r, l) in zip(ranges, final_rd_lat):
1262SN/A        print r, round(l, 2)
1272SN/A
1282SN/A    # lazy version to check if an integer is a power of two
1292SN/A    def is_pow2(num):
1302SN/A        return num != 0 and ((num & (num - 1)) == 0)
1312SN/A
1322SN/A    plt.semilogx(ranges, final_rd_lat)
1332SN/A
1342SN/A    # create human readable labels
1352SN/A    xticks_locations = [r for r in ranges if is_pow2(r)]
1362SN/A    xticks_labels = []
1372SN/A    for x in xticks_locations:
1382SN/A        if x < 1024:
1392SN/A            xticks_labels.append('%d kB' % x)
1402SN/A        else:
1412SN/A            xticks_labels.append('%d MB' % (x / 1024))
1422SN/A    plt.xticks(xticks_locations, xticks_labels, rotation=-45)
1432SN/A
1442SN/A    plt.minorticks_off()
1452SN/A    plt.xlim((xticks_locations[0], xticks_locations[-1]))
1462SN/A    plt.ylabel("Latency (ns)")
1472SN/A    plt.grid(True)
1482SN/A    plt.show()
1492SN/A
150180SN/Aif __name__ == "__main__":
1512680Sktlim@umich.edu    main()
1522SN/A