113540Sandrea.mondelli@ucf.edu#!/usr/bin/env python2.7 29048SAli.Saidi@ARM.com 311834SCurtis.Dunham@arm.com# Copyright (c) 2012-2013,2015-2016 ARM Limited 49048SAli.Saidi@ARM.com# All rights reserved 59048SAli.Saidi@ARM.com# 69048SAli.Saidi@ARM.com# The license below extends only to copyright in the software and shall 79048SAli.Saidi@ARM.com# not be construed as granting a license to any other intellectual 89048SAli.Saidi@ARM.com# property including but not limited to intellectual property relating 99048SAli.Saidi@ARM.com# to a hardware implementation of the functionality of the software 109048SAli.Saidi@ARM.com# licensed hereunder. You may use the software subject to the license 119048SAli.Saidi@ARM.com# terms below provided that you ensure that this notice is replicated 129048SAli.Saidi@ARM.com# unmodified and in its entirety in all distributions of the software, 139048SAli.Saidi@ARM.com# modified or unmodified, in source code or in binary form. 149048SAli.Saidi@ARM.com# 159048SAli.Saidi@ARM.com# Redistribution and use in source and binary forms, with or without 169048SAli.Saidi@ARM.com# modification, are permitted provided that the following conditions are 179048SAli.Saidi@ARM.com# met: redistributions of source code must retain the above copyright 189048SAli.Saidi@ARM.com# notice, this list of conditions and the following disclaimer; 199048SAli.Saidi@ARM.com# redistributions in binary form must reproduce the above copyright 209048SAli.Saidi@ARM.com# notice, this list of conditions and the following disclaimer in the 219048SAli.Saidi@ARM.com# documentation and/or other materials provided with the distribution; 229048SAli.Saidi@ARM.com# neither the name of the copyright holders nor the names of its 239048SAli.Saidi@ARM.com# contributors may be used to endorse or promote products derived from 249048SAli.Saidi@ARM.com# this software without specific prior written permission. 259048SAli.Saidi@ARM.com# 269048SAli.Saidi@ARM.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 279048SAli.Saidi@ARM.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 289048SAli.Saidi@ARM.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 299048SAli.Saidi@ARM.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 309048SAli.Saidi@ARM.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 319048SAli.Saidi@ARM.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 329048SAli.Saidi@ARM.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 339048SAli.Saidi@ARM.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 349048SAli.Saidi@ARM.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 359048SAli.Saidi@ARM.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 369048SAli.Saidi@ARM.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 379048SAli.Saidi@ARM.com# 389048SAli.Saidi@ARM.com# Authors: Ali Saidi 3911077SCurtis.Dunham@arm.com# Curtis Dunham 409048SAli.Saidi@ARM.com# 419048SAli.Saidi@ARM.com 429056SAli.Saidi@ARM.com# This python code is used to migrate checkpoints that were created in one 439056SAli.Saidi@ARM.com# version of the simulator to newer version. As features are added or bugs are 449056SAli.Saidi@ARM.com# fixed some of the state that needs to be checkpointed can change. If you have 459056SAli.Saidi@ARM.com# many historic checkpoints that you use, manually editing them to fix them is 469056SAli.Saidi@ARM.com# both time consuming and error-prone. 479056SAli.Saidi@ARM.com 489056SAli.Saidi@ARM.com# This script provides a way to migrate checkpoints to the newer repository in 4911077SCurtis.Dunham@arm.com# a programmatic way. It can be imported into another script or used on the 509056SAli.Saidi@ARM.com# command line. From the command line the script will either migrate every 519056SAli.Saidi@ARM.com# checkpoint it finds recursively (-r option) or a single checkpoint. When a 5211077SCurtis.Dunham@arm.com# change is made to the gem5 repository that breaks previous checkpoints an 5311077SCurtis.Dunham@arm.com# upgrade() method should be implemented in its own .py file and placed in 5411077SCurtis.Dunham@arm.com# src/util/cpt_upgraders/. For each upgrader whose tag is not present in 5511077SCurtis.Dunham@arm.com# the checkpoint tag list, the upgrade() method will be run, passing in a 5611077SCurtis.Dunham@arm.com# ConfigParser object which contains the open file. As these operations can 5711077SCurtis.Dunham@arm.com# be isa specific the method can verify the isa and use regexes to find the 5811077SCurtis.Dunham@arm.com# correct sections that need to be updated. 599056SAli.Saidi@ARM.com 6011834SCurtis.Dunham@arm.com# It is also possible to use this mechanism to revert prior tags. In this 6111834SCurtis.Dunham@arm.com# case, implement a downgrade() method instead. Dependencies should still 6211834SCurtis.Dunham@arm.com# work naturally - a tag depending on a tag with a downgrader means that it 6311834SCurtis.Dunham@arm.com# insists on the other tag being removed and its downgrader executed before 6411834SCurtis.Dunham@arm.com# its upgrader (or downgrader) can run. It is still the case that a tag 6511834SCurtis.Dunham@arm.com# can only be used once. 6611834SCurtis.Dunham@arm.com 6711835SCurtis.Dunham@arm.com# Dependencies between tags are expressed by two variables at the top-level 6811835SCurtis.Dunham@arm.com# of the upgrader script: "depends" can be either a string naming another 6911835SCurtis.Dunham@arm.com# tag that it depends upon or a list of such strings; and "fwd_depends" 7011835SCurtis.Dunham@arm.com# accepts the same datatypes but it reverses the sense of the dependency 7111835SCurtis.Dunham@arm.com# arrow(s) -- it expresses that that tag depends upon the tag of the current 7211835SCurtis.Dunham@arm.com# upgrader. This can be especially valuable when maintaining private 7311835SCurtis.Dunham@arm.com# upgraders in private branches. 7411835SCurtis.Dunham@arm.com 759056SAli.Saidi@ARM.com 769048SAli.Saidi@ARM.comimport ConfigParser 7711077SCurtis.Dunham@arm.comimport glob, types, sys, os 789048SAli.Saidi@ARM.comimport os.path as osp 799048SAli.Saidi@ARM.com 809048SAli.Saidi@ARM.comverbose_print = False 819048SAli.Saidi@ARM.com 829048SAli.Saidi@ARM.comdef verboseprint(*args): 839048SAli.Saidi@ARM.com if not verbose_print: 849048SAli.Saidi@ARM.com return 859048SAli.Saidi@ARM.com for arg in args: 869048SAli.Saidi@ARM.com print arg, 879048SAli.Saidi@ARM.com print 889048SAli.Saidi@ARM.com 8911077SCurtis.Dunham@arm.comclass Upgrader: 9011077SCurtis.Dunham@arm.com tag_set = set() 9111834SCurtis.Dunham@arm.com untag_set = set() # tags to remove by downgrading 9211077SCurtis.Dunham@arm.com by_tag = {} 9311077SCurtis.Dunham@arm.com legacy = {} 9411077SCurtis.Dunham@arm.com def __init__(self, filename): 9511077SCurtis.Dunham@arm.com self.filename = filename 9611077SCurtis.Dunham@arm.com execfile(filename, {}, self.__dict__) 9711077SCurtis.Dunham@arm.com 9811077SCurtis.Dunham@arm.com if not hasattr(self, 'tag'): 9911077SCurtis.Dunham@arm.com self.tag = osp.basename(filename)[:-3] 10011077SCurtis.Dunham@arm.com if not hasattr(self, 'depends'): 10111077SCurtis.Dunham@arm.com self.depends = [] 10211077SCurtis.Dunham@arm.com elif isinstance(self.depends, str): 10311077SCurtis.Dunham@arm.com self.depends = [self.depends] 10411077SCurtis.Dunham@arm.com 10511835SCurtis.Dunham@arm.com if not isinstance(self.depends, list): 10611835SCurtis.Dunham@arm.com print "Error: 'depends' for %s is the wrong type" % self.tag 10711835SCurtis.Dunham@arm.com sys.exit(1) 10811835SCurtis.Dunham@arm.com 10911835SCurtis.Dunham@arm.com if hasattr(self, 'fwd_depends'): 11011835SCurtis.Dunham@arm.com if isinstance(self.fwd_depends, str): 11111835SCurtis.Dunham@arm.com self.fwd_depends = [self.fwd_depends] 11211835SCurtis.Dunham@arm.com else: 11311835SCurtis.Dunham@arm.com self.fwd_depends = [] 11411835SCurtis.Dunham@arm.com 11511835SCurtis.Dunham@arm.com if not isinstance(self.fwd_depends, list): 11611835SCurtis.Dunham@arm.com print "Error: 'fwd_depends' for %s is the wrong type" % self.tag 11711835SCurtis.Dunham@arm.com sys.exit(1) 11811835SCurtis.Dunham@arm.com 11911834SCurtis.Dunham@arm.com if hasattr(self, 'upgrader'): 12011834SCurtis.Dunham@arm.com if not isinstance(self.upgrader, types.FunctionType): 12111834SCurtis.Dunham@arm.com print "Error: 'upgrader' for %s is %s, not function" \ 12211834SCurtis.Dunham@arm.com % (self.tag, type(self)) 12311834SCurtis.Dunham@arm.com sys.exit(1) 12411834SCurtis.Dunham@arm.com Upgrader.tag_set.add(self.tag) 12511834SCurtis.Dunham@arm.com elif hasattr(self, 'downgrader'): 12611834SCurtis.Dunham@arm.com if not isinstance(self.downgrader, types.FunctionType): 12711834SCurtis.Dunham@arm.com print "Error: 'downgrader' for %s is %s, not function" \ 12811834SCurtis.Dunham@arm.com % (self.tag, type(self)) 12911834SCurtis.Dunham@arm.com sys.exit(1) 13011834SCurtis.Dunham@arm.com Upgrader.untag_set.add(self.tag) 13111834SCurtis.Dunham@arm.com else: 13211834SCurtis.Dunham@arm.com print "Error: no upgrader or downgrader method for", self.tag 13311077SCurtis.Dunham@arm.com sys.exit(1) 13411077SCurtis.Dunham@arm.com 13511077SCurtis.Dunham@arm.com if hasattr(self, 'legacy_version'): 13611077SCurtis.Dunham@arm.com Upgrader.legacy[self.legacy_version] = self 13711077SCurtis.Dunham@arm.com 13811077SCurtis.Dunham@arm.com Upgrader.by_tag[self.tag] = self 13911077SCurtis.Dunham@arm.com 14011077SCurtis.Dunham@arm.com def ready(self, tags): 14111077SCurtis.Dunham@arm.com for dep in self.depends: 14211077SCurtis.Dunham@arm.com if dep not in tags: 14311077SCurtis.Dunham@arm.com return False 14411077SCurtis.Dunham@arm.com return True 14511077SCurtis.Dunham@arm.com 14611834SCurtis.Dunham@arm.com def update(self, cpt, tags): 14711834SCurtis.Dunham@arm.com if hasattr(self, 'upgrader'): 14811834SCurtis.Dunham@arm.com self.upgrader(cpt) 14911834SCurtis.Dunham@arm.com tags.add(self.tag) 15011834SCurtis.Dunham@arm.com verboseprint("applied upgrade for", self.tag) 15111834SCurtis.Dunham@arm.com else: 15211834SCurtis.Dunham@arm.com self.downgrader(cpt) 15311834SCurtis.Dunham@arm.com tags.remove(self.tag) 15411834SCurtis.Dunham@arm.com verboseprint("applied downgrade for", self.tag) 15511077SCurtis.Dunham@arm.com 15611077SCurtis.Dunham@arm.com @staticmethod 15711077SCurtis.Dunham@arm.com def get(tag): 15811077SCurtis.Dunham@arm.com return Upgrader.by_tag[tag] 15911077SCurtis.Dunham@arm.com 16011077SCurtis.Dunham@arm.com @staticmethod 16111077SCurtis.Dunham@arm.com def load_all(): 16211077SCurtis.Dunham@arm.com util_dir = osp.dirname(osp.abspath(__file__)) 16311077SCurtis.Dunham@arm.com 16411077SCurtis.Dunham@arm.com for py in glob.glob(util_dir + '/cpt_upgraders/*.py'): 16511077SCurtis.Dunham@arm.com Upgrader(py) 16611077SCurtis.Dunham@arm.com 16711077SCurtis.Dunham@arm.com # make linear dependences for legacy versions 16811077SCurtis.Dunham@arm.com i = 3 16911077SCurtis.Dunham@arm.com while i in Upgrader.legacy: 17011077SCurtis.Dunham@arm.com Upgrader.legacy[i].depends = [Upgrader.legacy[i-1].tag] 17111077SCurtis.Dunham@arm.com i = i + 1 17211077SCurtis.Dunham@arm.com 17311835SCurtis.Dunham@arm.com # resolve forward dependencies and audit normal dependencies 17411835SCurtis.Dunham@arm.com for tag, upg in Upgrader.by_tag.items(): 17511835SCurtis.Dunham@arm.com for fd in upg.fwd_depends: 17611835SCurtis.Dunham@arm.com if fd not in Upgrader.by_tag: 17711835SCurtis.Dunham@arm.com print "Error: '%s' cannot (forward) depend on "\ 17811835SCurtis.Dunham@arm.com "nonexistent tag '%s'" % (fd, tag) 17911835SCurtis.Dunham@arm.com sys.exit(1) 18011835SCurtis.Dunham@arm.com Upgrader.by_tag[fd].depends.append(tag) 18111835SCurtis.Dunham@arm.com for dep in upg.depends: 18211835SCurtis.Dunham@arm.com if dep not in Upgrader.by_tag: 18311835SCurtis.Dunham@arm.com print "Error: '%s' cannot depend on "\ 18411835SCurtis.Dunham@arm.com "nonexistent tag '%s'" % (tag, dep) 18511835SCurtis.Dunham@arm.com sys.exit(1) 18611835SCurtis.Dunham@arm.com 1879048SAli.Saidi@ARM.comdef process_file(path, **kwargs): 1889048SAli.Saidi@ARM.com if not osp.isfile(path): 1899048SAli.Saidi@ARM.com import errno 1909048SAli.Saidi@ARM.com raise IOError(ennro.ENOENT, "No such file", path) 1919048SAli.Saidi@ARM.com 1929048SAli.Saidi@ARM.com verboseprint("Processing file %s...." % path) 1939048SAli.Saidi@ARM.com 1949048SAli.Saidi@ARM.com if kwargs.get('backup', True): 1959048SAli.Saidi@ARM.com import shutil 1969048SAli.Saidi@ARM.com shutil.copyfile(path, path + '.bak') 1979048SAli.Saidi@ARM.com 1989048SAli.Saidi@ARM.com cpt = ConfigParser.SafeConfigParser() 1999048SAli.Saidi@ARM.com 2009048SAli.Saidi@ARM.com # gem5 is case sensitive with paramaters 2019048SAli.Saidi@ARM.com cpt.optionxform = str 2029048SAli.Saidi@ARM.com 2039048SAli.Saidi@ARM.com # Read the current data 2049048SAli.Saidi@ARM.com cpt_file = file(path, 'r') 2059048SAli.Saidi@ARM.com cpt.readfp(cpt_file) 2069048SAli.Saidi@ARM.com cpt_file.close() 2079048SAli.Saidi@ARM.com 20811077SCurtis.Dunham@arm.com change = False 20911077SCurtis.Dunham@arm.com 2109048SAli.Saidi@ARM.com # Make sure we know what we're starting from 21111077SCurtis.Dunham@arm.com if cpt.has_option('root','cpt_ver'): 21211077SCurtis.Dunham@arm.com cpt_ver = cpt.getint('root','cpt_ver') 2139048SAli.Saidi@ARM.com 21411077SCurtis.Dunham@arm.com # Legacy linear checkpoint version 21511077SCurtis.Dunham@arm.com # convert to list of tags before proceeding 21611077SCurtis.Dunham@arm.com tags = set([]) 21711077SCurtis.Dunham@arm.com for i in xrange(2, cpt_ver+1): 21811077SCurtis.Dunham@arm.com tags.add(Upgrader.legacy[i].tag) 21911077SCurtis.Dunham@arm.com verboseprint("performed legacy version -> tags conversion") 22011077SCurtis.Dunham@arm.com change = True 2219048SAli.Saidi@ARM.com 22211077SCurtis.Dunham@arm.com cpt.remove_option('root', 'cpt_ver') 22311077SCurtis.Dunham@arm.com elif cpt.has_option('Globals','version_tags'): 22411077SCurtis.Dunham@arm.com tags = set((''.join(cpt.get('Globals','version_tags'))).split()) 22511077SCurtis.Dunham@arm.com else: 22611077SCurtis.Dunham@arm.com print "fatal: no version information in checkpoint" 22711077SCurtis.Dunham@arm.com exit(1) 2289048SAli.Saidi@ARM.com 22911077SCurtis.Dunham@arm.com verboseprint("has tags", ' '.join(tags)) 23011077SCurtis.Dunham@arm.com # If the current checkpoint has a tag we don't know about, we have 23111077SCurtis.Dunham@arm.com # a divergence that (in general) must be addressed by (e.g.) merging 23211077SCurtis.Dunham@arm.com # simulator support for its changes. 23311834SCurtis.Dunham@arm.com unknown_tags = tags - (Upgrader.tag_set | Upgrader.untag_set) 23411077SCurtis.Dunham@arm.com if unknown_tags: 23511077SCurtis.Dunham@arm.com print "warning: upgrade script does not recognize the following "\ 23611077SCurtis.Dunham@arm.com "tags in this checkpoint:", ' '.join(unknown_tags) 2379048SAli.Saidi@ARM.com 23811834SCurtis.Dunham@arm.com # Apply migrations for tags not in checkpoint and tags present for which 23911834SCurtis.Dunham@arm.com # downgraders are present, respecting dependences 24011834SCurtis.Dunham@arm.com to_apply = (Upgrader.tag_set - tags) | (Upgrader.untag_set & tags) 24111077SCurtis.Dunham@arm.com while to_apply: 24211077SCurtis.Dunham@arm.com ready = set([ t for t in to_apply if Upgrader.get(t).ready(tags) ]) 24311077SCurtis.Dunham@arm.com if not ready: 24411077SCurtis.Dunham@arm.com print "could not apply these upgrades:", ' '.join(to_apply) 24511834SCurtis.Dunham@arm.com print "update dependences impossible to resolve; aborting" 24611077SCurtis.Dunham@arm.com exit(1) 24711077SCurtis.Dunham@arm.com 24811077SCurtis.Dunham@arm.com for tag in ready: 24911834SCurtis.Dunham@arm.com Upgrader.get(tag).update(cpt, tags) 25011077SCurtis.Dunham@arm.com change = True 25111077SCurtis.Dunham@arm.com 25211077SCurtis.Dunham@arm.com to_apply -= ready 25311077SCurtis.Dunham@arm.com 25411077SCurtis.Dunham@arm.com if not change: 25511077SCurtis.Dunham@arm.com verboseprint("...nothing to do") 2569048SAli.Saidi@ARM.com return 2579048SAli.Saidi@ARM.com 25811077SCurtis.Dunham@arm.com cpt.set('Globals', 'version_tags', ' '.join(tags)) 2599048SAli.Saidi@ARM.com 2609048SAli.Saidi@ARM.com # Write the old data back 26111077SCurtis.Dunham@arm.com verboseprint("...completed") 2629048SAli.Saidi@ARM.com cpt.write(file(path, 'w')) 2639048SAli.Saidi@ARM.com 2649048SAli.Saidi@ARM.comif __name__ == '__main__': 26511077SCurtis.Dunham@arm.com from optparse import OptionParser, SUPPRESS_HELP 2669048SAli.Saidi@ARM.com parser = OptionParser("usage: %prog [options] <filename or directory>") 2679048SAli.Saidi@ARM.com parser.add_option("-r", "--recurse", action="store_true", 2689048SAli.Saidi@ARM.com help="Recurse through all subdirectories modifying "\ 2699048SAli.Saidi@ARM.com "each checkpoint that is found") 2709048SAli.Saidi@ARM.com parser.add_option("-N", "--no-backup", action="store_false", 2719048SAli.Saidi@ARM.com dest="backup", default=True, 2729048SAli.Saidi@ARM.com help="Do no backup each checkpoint before modifying it") 2739048SAli.Saidi@ARM.com parser.add_option("-v", "--verbose", action="store_true", 2749048SAli.Saidi@ARM.com help="Print out debugging information as") 27511077SCurtis.Dunham@arm.com parser.add_option("--get-cc-file", action="store_true", 27611077SCurtis.Dunham@arm.com # used during build; generate src/sim/tags.cc and exit 27711077SCurtis.Dunham@arm.com help=SUPPRESS_HELP) 2789048SAli.Saidi@ARM.com 2799048SAli.Saidi@ARM.com (options, args) = parser.parse_args() 28011077SCurtis.Dunham@arm.com verbose_print = options.verbose 28111077SCurtis.Dunham@arm.com 28211077SCurtis.Dunham@arm.com Upgrader.load_all() 28311077SCurtis.Dunham@arm.com 28411077SCurtis.Dunham@arm.com if options.get_cc_file: 28511077SCurtis.Dunham@arm.com print "// this file is auto-generated by util/cpt_upgrader.py" 28611077SCurtis.Dunham@arm.com print "#include <string>" 28711077SCurtis.Dunham@arm.com print "#include <set>" 28811077SCurtis.Dunham@arm.com print 28911077SCurtis.Dunham@arm.com print "std::set<std::string> version_tags = {" 29011077SCurtis.Dunham@arm.com for tag in Upgrader.tag_set: 29111077SCurtis.Dunham@arm.com print " \"%s\"," % tag 29211077SCurtis.Dunham@arm.com print "};" 29311077SCurtis.Dunham@arm.com exit(0) 29411077SCurtis.Dunham@arm.com elif len(args) != 1: 2959048SAli.Saidi@ARM.com parser.error("You must specify a checkpoint file to modify or a "\ 2969048SAli.Saidi@ARM.com "directory of checkpoints to recursively update") 2979048SAli.Saidi@ARM.com 2989048SAli.Saidi@ARM.com # Deal with shell variables and ~ 2999048SAli.Saidi@ARM.com path = osp.expandvars(osp.expanduser(args[0])) 3009048SAli.Saidi@ARM.com 3019048SAli.Saidi@ARM.com # Process a single file if we have it 3029048SAli.Saidi@ARM.com if osp.isfile(path): 3039048SAli.Saidi@ARM.com process_file(path, **vars(options)) 3049048SAli.Saidi@ARM.com # Process an entire directory 3059048SAli.Saidi@ARM.com elif osp.isdir(path): 3069048SAli.Saidi@ARM.com cpt_file = osp.join(path, 'm5.cpt') 3079048SAli.Saidi@ARM.com if options.recurse: 3089048SAli.Saidi@ARM.com # Visit very file and see if it matches 3099048SAli.Saidi@ARM.com for root,dirs,files in os.walk(path): 3109048SAli.Saidi@ARM.com for name in files: 3119048SAli.Saidi@ARM.com if name == 'm5.cpt': 3129048SAli.Saidi@ARM.com process_file(osp.join(root,name), **vars(options)) 3139048SAli.Saidi@ARM.com for dir in dirs: 3149048SAli.Saidi@ARM.com pass 3159048SAli.Saidi@ARM.com # Maybe someone passed a cpt.XXXXXXX directory and not m5.cpt 3169048SAli.Saidi@ARM.com elif osp.isfile(cpt_file): 3179048SAli.Saidi@ARM.com process_file(cpt_file, **vars(options)) 3189048SAli.Saidi@ARM.com else: 3199048SAli.Saidi@ARM.com print "Error: checkpoint file not found at in %s " % path, 3209048SAli.Saidi@ARM.com print "and recurse not specified" 3219048SAli.Saidi@ARM.com sys.exit(1) 3229048SAli.Saidi@ARM.com sys.exit(0) 3239048SAli.Saidi@ARM.com 324