config: Add options to take/resume from SimPoint checkpoints
authorDam Sunwoo <dam.sunwoo@arm.com>
Tue, 23 Dec 2014 14:31:17 +0000 (09:31 -0500)
committerDam Sunwoo <dam.sunwoo@arm.com>
Tue, 23 Dec 2014 14:31:17 +0000 (09:31 -0500)
More documentation at http://gem5.org/Simpoints

Steps to profile, generate, and use SimPoints with gem5:

1. To profile workload and generate SimPoint BBV file, use the
following option:

--simpoint-profile --simpoint-interval <interval length>

Requires single Atomic CPU and fastmem.
<interval length> is in number of instructions.

2. Generate SimPoint analysis using SimPoint 3.2 from UCSD.
(SimPoint 3.2 not included with this flow.)

3. To take gem5 checkpoints based on SimPoint analysis, use the
following option:

--take-simpoint-checkpoint=<simpoint file path>,<weight file
path>,<interval length>,<warmup length>

<simpoint file> and <weight file> is generated by SimPoint analysis
tool from UCSD. SimPoint 3.2 format expected. <interval length> and
<warmup length> are in number of instructions.

4. To resume from gem5 SimPoint checkpoints, use the following option:

--restore-simpoint-checkpoint -r <N> --checkpoint-dir <simpoint
checkpoint path>

<N> is (SimPoint index + 1). E.g., "-r 1" will resume from SimPoint
#0.

configs/common/Options.py
configs/common/Simulation.py
configs/example/fs.py

index a788af290f9aeb1a07daafe0464a976a53f28319..cb5ffad2ec645107b04d784f5573bd10dec59be9 100644 (file)
@@ -150,6 +150,11 @@ def addCommonOptions(parser):
                       help="Enable basic block profiling for SimPoints")
     parser.add_option("--simpoint-interval", type="int", default=10000000,
                       help="SimPoint interval in num of instructions")
+    parser.add_option("--take-simpoint-checkpoints", action="store", type="string",
+        help="<simpoint file,weight file,interval-length,warmup-length>")
+    parser.add_option("--restore-simpoint-checkpoint", action="store_true",
+        help="restore from a simpoint checkpoint taken with " +
+             "--take-simpoint-checkpoints")
 
     # Checkpointing options
     ###Note that performing checkpointing via python script files will override
index 5d4398c80b7709296460e1920246dd039a6329fb..72d3d0e97f72fd81c35ef5d74281783ae6294786 100644 (file)
@@ -140,9 +140,46 @@ def findCptDir(options, cptdir, testsys):
         checkpoint_dir = joinpath(cptdir, "cpt.%s.%s" % (options.bench, inst))
         if not exists(checkpoint_dir):
             fatal("Unable to find checkpoint directory %s", checkpoint_dir)
+
+    elif options.restore_simpoint_checkpoint:
+        # Restore from SimPoint checkpoints
+        # Assumes that the checkpoint dir names are formatted as follows:
+        dirs = listdir(cptdir)
+        expr = re.compile('cpt\.simpoint_(\d+)_inst_(\d+)' +
+                    '_weight_([\d\.e\-]+)_interval_(\d+)_warmup_(\d+)')
+        cpts = []
+        for dir in dirs:
+            match = expr.match(dir)
+            if match:
+                cpts.append(dir)
+        cpts.sort()
+
+        cpt_num = options.checkpoint_restore
+        if cpt_num > len(cpts):
+            fatal('Checkpoint %d not found', cpt_num)
+        checkpoint_dir = joinpath(cptdir, cpts[cpt_num - 1])
+        match = expr.match(cpts[cpt_num - 1])
+        if match:
+            index = int(match.group(1))
+            start_inst = int(match.group(2))
+            weight_inst = float(match.group(3))
+            interval_length = int(match.group(4))
+            warmup_length = int(match.group(5))
+        print "Resuming from", checkpoint_dir
+        simpoint_start_insts = []
+        simpoint_start_insts.append(warmup_length)
+        simpoint_start_insts.append(warmup_length + interval_length)
+        testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
+        if testsys.switch_cpus != None:
+            testsys.switch_cpus[0].simpoint_start_insts = simpoint_start_insts
+
+        print "Resuming from SimPoint",
+        print "#%d, start_inst:%d, weight:%f, interval:%d, warmup:%d" % \
+            (index, start_inst, weight_inst, interval_length, warmup_length)
+
     else:
         dirs = listdir(cptdir)
-        expr = re.compile('cpt\.([0-9]*)')
+        expr = re.compile('cpt\.([0-9]+)')
         cpts = []
         for dir in dirs:
             match = expr.match(dir)
@@ -239,6 +276,131 @@ def benchCheckpoints(options, maxtick, cptdir):
 
     return exit_event
 
+# Set up environment for taking SimPoint checkpoints
+# Expecting SimPoint files generated by SimPoint 3.2
+def parseSimpointAnalysisFile(options, testsys):
+    import re
+
+    simpoint_filename, weight_filename, interval_length, warmup_length = \
+        options.take_simpoint_checkpoints.split(",", 3)
+    print "simpoint analysis file:", simpoint_filename
+    print "simpoint weight file:", weight_filename
+    print "interval length:", interval_length
+    print "warmup length:", warmup_length
+
+    interval_length = int(interval_length)
+    warmup_length = int(warmup_length)
+
+    # Simpoint analysis output starts interval counts with 0.
+    simpoints = []
+    simpoint_start_insts = []
+
+    # Read in SimPoint analysis files
+    simpoint_file = open(simpoint_filename)
+    weight_file = open(weight_filename)
+    while True:
+        line = simpoint_file.readline()
+        if not line:
+            break
+        m = re.match("(\d+)\s+(\d+)", line)
+        if m:
+            interval = int(m.group(1))
+        else:
+            fatal('unrecognized line in simpoint file!')
+
+        line = weight_file.readline()
+        if not line:
+            fatal('not enough lines in simpoint weight file!')
+        m = re.match("([0-9\.e\-]+)\s+(\d+)", line)
+        if m:
+            weight = float(m.group(1))
+        else:
+            fatal('unrecognized line in simpoint weight file!')
+
+        if (interval * interval_length - warmup_length > 0):
+            starting_inst_count = \
+                interval * interval_length - warmup_length
+            actual_warmup_length = warmup_length
+        else:
+            # Not enough room for proper warmup
+            # Just starting from the beginning
+            starting_inst_count = 0
+            actual_warmup_length = interval * interval_length
+
+        simpoints.append((interval, weight, starting_inst_count,
+            actual_warmup_length))
+
+    # Sort SimPoints by starting inst count
+    simpoints.sort(key=lambda obj: obj[2])
+    for s in simpoints:
+        interval, weight, starting_inst_count, actual_warmup_length = s
+        print str(interval), str(weight), starting_inst_count, \
+            actual_warmup_length
+        simpoint_start_insts.append(starting_inst_count)
+
+    print "Total # of simpoints:", len(simpoints)
+    testsys.cpu[0].simpoint_start_insts = simpoint_start_insts
+
+    return (simpoints, interval_length)
+
+def takeSimpointCheckpoints(simpoints, interval_length, cptdir):
+    num_checkpoints = 0
+    index = 0
+    last_chkpnt_inst_count = -1
+    for simpoint in simpoints:
+        interval, weight, starting_inst_count, actual_warmup_length = simpoint
+        if starting_inst_count == last_chkpnt_inst_count:
+            # checkpoint starting point same as last time
+            # (when warmup period longer than starting point)
+            exit_cause = "simpoint starting point found"
+            code = 0
+        else:
+            exit_event = m5.simulate()
+
+            # skip checkpoint instructions should they exist
+            while exit_event.getCause() == "checkpoint":
+                print "Found 'checkpoint' exit event...ignoring..."
+                exit_event = m5.simulate()
+
+            exit_cause = exit_event.getCause()
+            code = exit_event.getCode()
+
+        if exit_cause == "simpoint starting point found":
+            m5.checkpoint(joinpath(cptdir,
+                "cpt.simpoint_%02d_inst_%d_weight_%f_interval_%d_warmup_%d"
+                % (index, starting_inst_count, weight, interval_length,
+                actual_warmup_length)))
+            print "Checkpoint #%d written. start inst:%d weight:%f" % \
+                (num_checkpoints, starting_inst_count, weight)
+            num_checkpoints += 1
+            last_chkpnt_inst_count = starting_inst_count
+        else:
+            break
+        index += 1
+
+    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
+    print "%d checkpoints taken" % num_checkpoints
+    sys.exit(code)
+
+def restoreSimpointCheckpoint():
+    exit_event = m5.simulate()
+    exit_cause = exit_event.getCause()
+
+    if exit_cause == "simpoint starting point found":
+        print "Warmed up! Dumping and resetting stats!"
+        m5.stats.dump()
+        m5.stats.reset()
+
+        exit_event = m5.simulate()
+        exit_cause = exit_event.getCause()
+
+        if exit_cause == "simpoint starting point found":
+            print "Done running SimPoint!"
+            sys.exit(exit_event.getCode())
+
+    print 'Exiting @ tick %i because %s' % (m5.curTick(), exit_cause)
+    sys.exit(exit_event.getCode())
+
 def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq):
     print "starting switch loop"
     while True:
@@ -411,6 +573,9 @@ def run(options, root, testsys, cpu_class):
             for i in xrange(np):
                 testsys.cpu[i].max_insts_any_thread = offset
 
+    if options.take_simpoint_checkpoints != None:
+        simpoints, interval_length = parseSimpointAnalysisFile(options, testsys)
+
     checkpoint_dir = None
     if options.checkpoint_restore:
         cpt_starttick, checkpoint_dir = findCptDir(options, cptdir, testsys)
@@ -485,7 +650,9 @@ def run(options, root, testsys, cpu_class):
     # option only for finding the checkpoints to restore from.  This
     # lets us test checkpointing by restoring from one set of
     # checkpoints, generating a second set, and then comparing them.
-    if options.take_checkpoints and options.checkpoint_restore:
+    if (options.take_checkpoints or options.take_simpoint_checkpoints) \
+        and options.checkpoint_restore:
+
         if m5.options.outdir:
             cptdir = m5.options.outdir
         else:
@@ -497,6 +664,15 @@ def run(options, root, testsys, cpu_class):
         # received from the benchmark running are ignored and skipped in
         # favor of command line checkpoint instructions.
         exit_event = scriptCheckpoints(options, maxtick, cptdir)
+
+    # Take SimPoint checkpoints
+    elif options.take_simpoint_checkpoints != None:
+        takeSimpointCheckpoints(simpoints, interval_length, cptdir)
+
+    # Restore from SimPoint checkpoints
+    elif options.restore_simpoint_checkpoint != None:
+        restoreSimpointCheckpoint()
+
     else:
         if options.fast_forward:
             m5.stats.reset()
index 62a298559de964d26ce7533dbf3dc6651c63b7b0..6fa0f8a11431beaa50bf4a2274db755beef59921 100644 (file)
@@ -197,9 +197,18 @@ def build_test_system(np):
             if (options.caches or options.l2cache):
                 fatal("You cannot use fastmem in combination with caches!")
 
+        if options.simpoint_profile:
+            if not options.fastmem:
+                # Atomic CPU checked with fastmem option already
+                fatal("SimPoint generation should be done with atomic cpu and fastmem")
+            if np > 1:
+                fatal("SimPoint generation not supported with more than one CPUs")
+
         for i in xrange(np):
             if options.fastmem:
                 test_sys.cpu[i].fastmem = True
+            if options.simpoint_profile:
+                test_sys.cpu[i].addSimPointProbe(options.simpoint_interval)
             if options.checker:
                 test_sys.cpu[i].addCheckerCpu()
             test_sys.cpu[i].createThreads()