memtest.py revision 10720
14467Sstever@eecs.umich.edu# Copyright (c) 2015 ARM Limited 23354Srdreslin@umich.edu# All rights reserved. 33354Srdreslin@umich.edu# 43354Srdreslin@umich.edu# The license below extends only to copyright in the software and shall 53354Srdreslin@umich.edu# not be construed as granting a license to any other intellectual 63354Srdreslin@umich.edu# property including but not limited to intellectual property relating 73354Srdreslin@umich.edu# to a hardware implementation of the functionality of the software 83354Srdreslin@umich.edu# licensed hereunder. You may use the software subject to the license 93354Srdreslin@umich.edu# terms below provided that you ensure that this notice is replicated 103354Srdreslin@umich.edu# unmodified and in its entirety in all distributions of the software, 113354Srdreslin@umich.edu# modified or unmodified, in source code or in binary form. 123354Srdreslin@umich.edu# 133354Srdreslin@umich.edu# Copyright (c) 2006-2007 The Regents of The University of Michigan 143354Srdreslin@umich.edu# All rights reserved. 153354Srdreslin@umich.edu# 163354Srdreslin@umich.edu# Redistribution and use in source and binary forms, with or without 173354Srdreslin@umich.edu# modification, are permitted provided that the following conditions are 183354Srdreslin@umich.edu# met: redistributions of source code must retain the above copyright 193354Srdreslin@umich.edu# notice, this list of conditions and the following disclaimer; 203354Srdreslin@umich.edu# redistributions in binary form must reproduce the above copyright 213354Srdreslin@umich.edu# notice, this list of conditions and the following disclaimer in the 223354Srdreslin@umich.edu# documentation and/or other materials provided with the distribution; 233354Srdreslin@umich.edu# neither the name of the copyright holders nor the names of its 243354Srdreslin@umich.edu# contributors may be used to endorse or promote products derived from 253354Srdreslin@umich.edu# this software without specific prior written permission. 263354Srdreslin@umich.edu# 273354Srdreslin@umich.edu# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 283354Srdreslin@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 296654Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 306654Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 316654Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 323354Srdreslin@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 333354Srdreslin@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 343354Srdreslin@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 353354Srdreslin@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 363354Srdreslin@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 374626Sstever@eecs.umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 384626Sstever@eecs.umich.edu# 394626Sstever@eecs.umich.edu# Authors: Ron Dreslinski 404626Sstever@eecs.umich.edu# Andreas Hansson 414893Sstever@eecs.umich.edu 424892Sstever@eecs.umich.eduimport optparse 434626Sstever@eecs.umich.eduimport sys 444626Sstever@eecs.umich.edu 454626Sstever@eecs.umich.eduimport m5 464626Sstever@eecs.umich.edufrom m5.objects import * 474892Sstever@eecs.umich.edu 484892Sstever@eecs.umich.eduparser = optparse.OptionParser() 494892Sstever@eecs.umich.edu 504892Sstever@eecs.umich.eduparser.add_option("-a", "--atomic", action="store_true", 514892Sstever@eecs.umich.edu help="Use atomic (non-timing) mode") 524892Sstever@eecs.umich.eduparser.add_option("-b", "--blocking", action="store_true", 534892Sstever@eecs.umich.edu help="Use blocking caches") 544892Sstever@eecs.umich.eduparser.add_option("-l", "--maxloads", metavar="N", default=0, 554892Sstever@eecs.umich.edu help="Stop after N loads") 564892Sstever@eecs.umich.eduparser.add_option("-m", "--maxtick", type="int", default=m5.MaxTick, 574892Sstever@eecs.umich.edu metavar="T", 584892Sstever@eecs.umich.edu help="Stop after T ticks") 594892Sstever@eecs.umich.edu 604892Sstever@eecs.umich.edu# This example script stress tests the memory system by creating false 614892Sstever@eecs.umich.edu# sharing in a tree topology. At the bottom of the tree is a shared 624892Sstever@eecs.umich.edu# memory, and then at each level a number of testers are attached, 634892Sstever@eecs.umich.edu# along with a number of caches that them selves fan out to subtrees 644892Sstever@eecs.umich.edu# of testers and caches. Thus, it is possible to create a system with 654892Sstever@eecs.umich.edu# arbitrarily deep cache hierarchies, sharing or no sharing of caches, 664892Sstever@eecs.umich.edu# and testers not only at the L1s, but also at the L2s, L3s etc. 674892Sstever@eecs.umich.edu# 684892Sstever@eecs.umich.edu# The tree specification consists of two colon-separated lists of one 694890Sstever@eecs.umich.edu# or more integers, one for the caches, and one for the testers. The 704891Sstever@eecs.umich.edu# first integer is the number of caches/testers closest to main 714891Sstever@eecs.umich.edu# memory. Each cache then fans out to a subtree. The last integer in 724890Sstever@eecs.umich.edu# the list is the number of caches/testers associated with the 734626Sstever@eecs.umich.edu# uppermost level of memory. The other integers (if any) specify the 744626Sstever@eecs.umich.edu# number of caches/testers connected at each level of the crossbar 754626Sstever@eecs.umich.edu# hierarchy. The tester string should have one element more than the 764626Sstever@eecs.umich.edu# cache string as there should always be testers attached to the 774626Sstever@eecs.umich.edu# uppermost caches. 784626Sstever@eecs.umich.edu 794626Sstever@eecs.umich.eduparser.add_option("-c", "--caches", type="string", default="2:2:1", 804626Sstever@eecs.umich.edu help="Colon-separated cache hierarchy specification, " 813354Srdreslin@umich.edu "see script comments for details " 824628Sstever@eecs.umich.edu "[default: %default]") 834628Sstever@eecs.umich.eduparser.add_option("-t", "--testers", type="string", default="1:1:0:2", 844628Sstever@eecs.umich.edu help="Colon-separated tester hierarchy specification, " 854628Sstever@eecs.umich.edu "see script comments for details " 864628Sstever@eecs.umich.edu "[default: %default]") 873354Srdreslin@umich.eduparser.add_option("-f", "--functional", type="int", default=0, 883354Srdreslin@umich.edu metavar="PCT", 893354Srdreslin@umich.edu help="Target percentage of functional accesses " 903354Srdreslin@umich.edu "[default: %default]") 913354Srdreslin@umich.eduparser.add_option("-u", "--uncacheable", type="int", default=0, 923354Srdreslin@umich.edu metavar="PCT", 934626Sstever@eecs.umich.edu help="Target percentage of uncacheable accesses " 944626Sstever@eecs.umich.edu "[default: %default]") 954892Sstever@eecs.umich.edu 964892Sstever@eecs.umich.eduparser.add_option("--progress", type="int", default=10000, 974892Sstever@eecs.umich.edu metavar="NLOADS", 984892Sstever@eecs.umich.edu help="Progress message interval " 994892Sstever@eecs.umich.edu "[default: %default]") 1004892Sstever@eecs.umich.eduparser.add_option("--sys-clock", action="store", type="string", 1013354Srdreslin@umich.edu default='1GHz', 1024890Sstever@eecs.umich.edu help = """Top-level clock for blocks running at system 1034626Sstever@eecs.umich.edu speed""") 1044626Sstever@eecs.umich.edu 1054626Sstever@eecs.umich.edu(options, args) = parser.parse_args() 1063354Srdreslin@umich.edu 1074890Sstever@eecs.umich.eduif args: 1084890Sstever@eecs.umich.edu print "Error: script doesn't take any positional arguments" 1094890Sstever@eecs.umich.edu sys.exit(1) 1104890Sstever@eecs.umich.edu 1114890Sstever@eecs.umich.edublock_size = 64 1124890Sstever@eecs.umich.edu 1134890Sstever@eecs.umich.edu# Start by parsing the command line options and do some basic sanity 1144890Sstever@eecs.umich.edu# checking 1154890Sstever@eecs.umich.edutry: 1164890Sstever@eecs.umich.edu cachespec = [int(x) for x in options.caches.split(':')] 1174890Sstever@eecs.umich.edu testerspec = [int(x) for x in options.testers.split(':')] 1184890Sstever@eecs.umich.eduexcept: 1194890Sstever@eecs.umich.edu print "Error: Unable to parse caches or testers option" 1204893Sstever@eecs.umich.edu sys.exit(1) 1214893Sstever@eecs.umich.edu 1224893Sstever@eecs.umich.eduif len(cachespec) < 1: 1234890Sstever@eecs.umich.edu print "Error: Must have at least one level of caches" 1244890Sstever@eecs.umich.edu sys.exit(1) 1254890Sstever@eecs.umich.edu 1264890Sstever@eecs.umich.eduif len(cachespec) != len(testerspec) - 1: 1274893Sstever@eecs.umich.edu print "Error: Testers must have one element more than caches" 1284893Sstever@eecs.umich.edu sys.exit(1) 1294893Sstever@eecs.umich.edu 1304893Sstever@eecs.umich.eduif testerspec[-1] == 0: 1314893Sstever@eecs.umich.edu print "Error: Must have testers at the uppermost level" 1324890Sstever@eecs.umich.edu sys.exit(1) 1334890Sstever@eecs.umich.edu 1344890Sstever@eecs.umich.edufor t in testerspec: 1354890Sstever@eecs.umich.edu if t < 0: 1364890Sstever@eecs.umich.edu print "Error: Cannot have a negative number of testers" 1374890Sstever@eecs.umich.edu sys.exit(1) 1384890Sstever@eecs.umich.edu 1394890Sstever@eecs.umich.edufor c in cachespec: 1404467Sstever@eecs.umich.edu if c < 1: 1413354Srdreslin@umich.edu print "Error: Must have 1 or more caches at each level" 1424890Sstever@eecs.umich.edu sys.exit(1) 1434890Sstever@eecs.umich.edu 1443354Srdreslin@umich.edu# Determine the tester multiplier for each level as the string 1454890Sstever@eecs.umich.edu# elements are per subsystem and it fans out 1464890Sstever@eecs.umich.edumultiplier = [1] 1474890Sstever@eecs.umich.edufor c in cachespec: 1484895Sstever@eecs.umich.edu if c < 1: 1494890Sstever@eecs.umich.edu print "Error: Must have at least one cache per level" 1504890Sstever@eecs.umich.edu multiplier.append(multiplier[-1] * c) 1514890Sstever@eecs.umich.edu 1524890Sstever@eecs.umich.edunumtesters = 0 1534890Sstever@eecs.umich.edufor t, m in zip(testerspec, multiplier): 1544890Sstever@eecs.umich.edu numtesters += t * m 1554890Sstever@eecs.umich.edu 1564890Sstever@eecs.umich.eduif numtesters > block_size: 1574890Sstever@eecs.umich.edu print "Error: Number of testers limited to %s because of false sharing" \ 1584890Sstever@eecs.umich.edu % (block_size) 1594890Sstever@eecs.umich.edu sys.exit(1) 1604890Sstever@eecs.umich.edu 1614890Sstever@eecs.umich.edu# Define a prototype L1 cache that we scale for all successive levels 1624890Sstever@eecs.umich.eduproto_l1 = BaseCache(size = '32kB', assoc = 4, 1634890Sstever@eecs.umich.edu hit_latency = 1, response_latency = 1, 1644890Sstever@eecs.umich.edu tgts_per_mshr = 8, is_top_level = True) 1654890Sstever@eecs.umich.edu 1664890Sstever@eecs.umich.eduif options.blocking: 1673354Srdreslin@umich.edu proto_l1.mshrs = 1 1684890Sstever@eecs.umich.eduelse: 1693354Srdreslin@umich.edu proto_l1.mshrs = 4 1703354Srdreslin@umich.edu 1713354Srdreslin@umich.educache_proto = [proto_l1] 1723354Srdreslin@umich.edu 1733354Srdreslin@umich.edu# Now add additional cache levels (if any) by scaling L1 params, the 1743354Srdreslin@umich.edu# first element is Ln, and the last element L1 1754626Sstever@eecs.umich.edufor scale in cachespec[:-1]: 1764626Sstever@eecs.umich.edu # Clone previous level and update params 1774626Sstever@eecs.umich.edu prev = cache_proto[0] 1783354Srdreslin@umich.edu next = prev() 1793354Srdreslin@umich.edu next.size = prev.size * scale 1804476Sstever@eecs.umich.edu next.hit_latency = prev.hit_latency * 10 1814476Sstever@eecs.umich.edu next.response_latency = prev.response_latency * 10 1824476Sstever@eecs.umich.edu next.assoc = prev.assoc * scale 1833354Srdreslin@umich.edu next.mshrs = prev.mshrs * scale 1843354Srdreslin@umich.edu next.is_top_level = False 1853354Srdreslin@umich.edu cache_proto.insert(0, next) 1863354Srdreslin@umich.edu 1874626Sstever@eecs.umich.edu# Make a prototype for the tester to be used throughout 1883354Srdreslin@umich.eduproto_tester = MemTest(max_loads = options.maxloads, 1893354Srdreslin@umich.edu percent_functional = options.functional, 190 percent_uncacheable = options.uncacheable, 191 progress_interval = options.progress) 192 193# Set up the system along with a simple memory and reference memory 194system = System(physmem = SimpleMemory(), 195 cache_line_size = block_size) 196 197system.voltage_domain = VoltageDomain(voltage = '1V') 198 199system.clk_domain = SrcClockDomain(clock = options.sys_clock, 200 voltage_domain = system.voltage_domain) 201 202# For each level, track the next subsys index to use 203next_subsys_index = [0] * (len(cachespec) + 1) 204 205# Recursive function to create a sub-tree of the cache and tester 206# hierarchy 207def make_cache_level(ncaches, prototypes, level, next_cache): 208 global next_subsys_index, proto_l1, testerspec, proto_tester 209 210 index = next_subsys_index[level] 211 next_subsys_index[level] += 1 212 213 # Create a subsystem to contain the crossbar and caches, and 214 # any testers 215 subsys = SubSystem() 216 setattr(system, 'l%dsubsys%d' % (level, index), subsys) 217 218 # The levels are indexing backwards through the list 219 ntesters = testerspec[len(cachespec) - level] 220 221 # Scale the progress threshold as testers higher up in the tree 222 # (smaller level) get a smaller portion of the overall bandwidth, 223 # and also make the interval of packet injection longer for the 224 # testers closer to the memory (larger level) to prevent them 225 # hogging all the bandwidth 226 limit = (len(cachespec) - level + 1) * 10000000 227 testers = [proto_tester(interval = 10 * (level * level + 1), 228 progress_check = limit) \ 229 for i in xrange(ntesters)] 230 if ntesters: 231 subsys.tester = testers 232 233 if level != 0: 234 # Create a crossbar and add it to the subsystem, note that 235 # we do this even with a single element on this level 236 xbar = L2XBar() 237 subsys.xbar = xbar 238 if next_cache: 239 xbar.master = next_cache.cpu_side 240 241 # Create and connect the caches, both the ones fanning out 242 # to create the tree, and the ones used to connect testers 243 # on this level 244 tree_caches = [prototypes[0]() for i in xrange(ncaches[0])] 245 tester_caches = [proto_l1() for i in xrange(ntesters)] 246 247 subsys.cache = tester_caches + tree_caches 248 for cache in tree_caches: 249 cache.mem_side = xbar.slave 250 make_cache_level(ncaches[1:], prototypes[1:], level - 1, cache) 251 for tester, cache in zip(testers, tester_caches): 252 tester.port = cache.cpu_side 253 cache.mem_side = xbar.slave 254 else: 255 if not next_cache: 256 print "Error: No next-level cache at top level" 257 sys.exit(1) 258 259 if ntesters > 1: 260 # Create a crossbar and add it to the subsystem 261 xbar = L2XBar() 262 subsys.xbar = xbar 263 xbar.master = next_cache.cpu_side 264 for tester in testers: 265 tester.port = xbar.slave 266 else: 267 # Single tester 268 testers[0].port = next_cache.cpu_side 269 270# Top level call to create the cache hierarchy, bottom up 271make_cache_level(cachespec, cache_proto, len(cachespec), None) 272 273# Connect the lowest level crossbar to the memory 274last_subsys = getattr(system, 'l%dsubsys0' % len(cachespec)) 275last_subsys.xbar.master = system.physmem.port 276 277root = Root(full_system = False, system = system) 278if options.atomic: 279 root.system.mem_mode = 'atomic' 280else: 281 root.system.mem_mode = 'timing' 282 283# The system port is never used in the tester so merely connect it 284# to avoid problems 285root.system.system_port = last_subsys.xbar.slave 286 287# Instantiate configuration 288m5.instantiate() 289 290# Simulate until program terminates 291exit_event = m5.simulate(options.maxtick) 292 293print 'Exiting @ tick', m5.curTick(), 'because', exit_event.getCause() 294