Synced repos to: 60588
diff --git a/crosperf/autotest_runner.py b/crosperf/autotest_runner.py
index 3b91d81..80fb2a2 100644
--- a/crosperf/autotest_runner.py
+++ b/crosperf/autotest_runner.py
@@ -6,18 +6,15 @@
 
 
 class AutotestRunner(object):
+  """ This defines the interface from crosperf to ./run_remote_tests.sh.
+  """
   def __init__(self, logger_to_use=None):
     self._logger = logger_to_use
     self._ce = command_executer.GetCommandExecuter(self._logger)
     self._ct = command_executer.CommandTerminator()
 
   def Run(self, machine_name, chromeos_root, board, autotest_name,
-          autotest_args, profile_counters, profile_type):
-    if profile_counters and profile_type:
-      profiler_args = "-e " + " -e ".join(profile_counters)
-      # TODO(asharif): Add an option to do -g.
-      autotest_args += (" --profile --profiler_args='%s' --profile_type='%s'"
-                        % (profiler_args, profile_type))
+          autotest_args):
     options = ""
     if board:
       options += " --board=%s" % board
diff --git a/crosperf/benchmark_run.py b/crosperf/benchmark_run.py
index f7c37c3..9b50bac 100644
--- a/crosperf/benchmark_run.py
+++ b/crosperf/benchmark_run.py
@@ -35,14 +35,12 @@
     self._logger = logger_to_use
     self.benchmark_name = benchmark_name
     self.autotest_name = autotest_name
-    self.autotest_args = autotest_args
     self.label_name = label_name
     self.chromeos_root = chromeos_root
     self.chromeos_image = os.path.expanduser(chromeos_image)
     self.board = board
     self.iteration = iteration
     self.result = None
-    self.results = {}
     self.terminated = False
     self.retval = None
     self.status = STATUS_PENDING
@@ -61,43 +59,9 @@
     self.cache_hit = False
     self.perf_results = None
     self.failure_reason = ""
+    self.autotest_args = "%s %s" % (autotest_args, self._GetExtraAutotestArgs())
     self._ce = command_executer.GetCommandExecuter(self._logger)
 
-  def ProcessResults(self):
-    # Generate results from the output file.
-    self.full_name = os.path.basename(self.results_dir)
-    self.results = self.result.keyvals
-
-    # Store the autotest output in the cache also.
-    if not self.cache_hit:
-      self.cache.StoreResult(self.result)
-      self.cache.StoreAutotestOutput(self.results_dir)
-
-    self.perf_processor = PerfProcessor(self.results_dir,
-                                        self.chromeos_root,
-                                        self.board,
-                                        self._logger)
-    # Generate a perf report and cache it.
-    if self.profile_type:
-      if self.cache_hit:
-        self.perf_results = self.cache.ReadPerfResults()
-      else:
-        self.perf_results = self.perf_processor.GeneratePerfResults()
-        self.cache.StorePerfResults(self.perf_results)
-
-    # If there are valid results from perf stat, combine them with the
-    # autotest results.
-    if self.perf_results:
-      stat_results = self.perf_processor.ParseStatResults(self.perf_results)
-      self.results = dict(self.results.items() + stat_results.items())
-
-  def _GetResultsDir(self, output):
-    mo = re.search("Results placed in (\S+)", output)
-    if mo:
-      result = mo.group(1)
-      return result
-    raise Exception("Could not find results directory.")
-
   def run(self):
     try:
       # Just use the first machine for running the cached version,
@@ -118,7 +82,6 @@
       if self.result:
         self._logger.LogOutput("%s: Cache hit." % self.name)
         self._logger.LogOutput(self.result.out + "\n" + self.result.err)
-        self.results_dir = self._GetResultsDir(self.result.out)
       else:
         self._logger.LogOutput("%s: No cache hit." % self.name)
         self.status = STATUS_WAITING
@@ -126,6 +89,7 @@
         self.machine = self.AcquireMachine()
         self.cache.remote = self.machine.name
         self.result = self.RunTest(self.machine)
+        self.cache.StoreResult(self.result)
 
       if self.terminated:
         return
@@ -137,8 +101,6 @@
           self.status = STATUS_FAILED
           self.failure_reason = "Return value of autotest was non-zero."
 
-      self.ProcessResults()
-
     except Exception, e:
       self._logger.LogError("Benchmark run: '%s' failed: %s" % (self.name, e))
       traceback.print_exc()
@@ -174,6 +136,21 @@
         time.sleep(sleep_duration)
     return machine
 
+  def _GetExtraAutotestArgs(self):
+    if self.profile_type:
+      if self.profile_type == "record":
+        perf_args = "record -a -e %s" % ",".join(self.profile_counters)
+      elif self.profile_type == "stat":
+        perf_args = "stat -a"
+      else:
+        raise Exception("profile_type must be either record or stat")
+      extra_autotest_args = ["--profiler=custom_perf",
+                             ("--profiler_args='perf_options=\"%s\"'" %
+                              perf_args)]
+      return " ".join(extra_autotest_args)
+    else:
+      return ""
+
   def RunTest(self, machine):
     self.status = STATUS_IMAGING
     self.machine_manager.ImageMachine(machine,
@@ -184,41 +161,15 @@
                                                   self.chromeos_root,
                                                   self.board,
                                                   self.autotest_name,
-                                                  self.autotest_args,
-                                                  self.profile_counters,
-                                                  self.profile_type)
+                                                  self.autotest_args)
     self.run_completed = True
 
-    # Include the keyvals in the result.
-    self.results_dir = self._GetResultsDir(out)
-    keyvals = self._GetKeyvals()
-    keyvals["retval"] = retval
-
-    result = Result(out, err, retval, keyvals)
-
-    return result
-
-  def _GetKeyvals(self):
-    full_results_dir = os.path.join(self.chromeos_root,
-                                    "chroot",
-                                    self.results_dir.lstrip("/"))
-    command = "find %s -regex .*results/keyval$" % full_results_dir
-    [ret, out, err] = self._ce.RunCommand(command, return_output=True)
-    keyvals_dict = {}
-    for f in out.splitlines():
-      keyvals = open(f, "r").read()
-      keyvals_dict.update(self._ParseKeyvals(keyvals))
-
-    return keyvals_dict
-
-  def _ParseKeyvals(self, keyvals):
-    keyval_dict = {}
-    for l in keyvals.splitlines():
-      l = l.strip()
-      if l:
-        key, val = l.split("=")
-        keyval_dict[key] = val
-    return keyval_dict
+    return Result.CreateFromRun(self._logger,
+                                self.chromeos_root,
+                                self.board,
+                                out,
+                                err,
+                                retval)
 
   def SetCacheConditions(self, cache_conditions):
     self.cache_conditions = cache_conditions
diff --git a/crosperf/experiment_runner.py b/crosperf/experiment_runner.py
index 6b73f5d..c5cd1ad 100644
--- a/crosperf/experiment_runner.py
+++ b/crosperf/experiment_runner.py
@@ -90,22 +90,9 @@
     self.l.LogOutput("Storing results of each benchmark run.")
     for benchmark_run in experiment.benchmark_runs:
       benchmark_run_name = filter(str.isalnum, benchmark_run.name)
-      try:
-        if benchmark_run.perf_results:
-          benchmark_run_path = os.path.join(results_directory,
-                                            benchmark_run_name)
-          FileUtils().MkDirP(benchmark_run_path)
-          FileUtils().WriteFile(os.path.join(benchmark_run_path, "perf.report"),
-                                benchmark_run.perf_results.report)
-          FileUtils().WriteFile(os.path.join(benchmark_run_path, "perf.out"),
-                                benchmark_run.perf_results.output)
-          if os.path.isfile(benchmark_run.perf_processor.host_data_file):
-            self._ce.RunCommand("cp %s %s" %
-                                (benchmark_run.perf_processor.host_data_file,
-                                 os.path.join(benchmark_run_path, "perf.data")))
-
-      except Exception, e:
-        self.l.LogError(e)
+      benchmark_run_path = os.path.join(results_directory,
+                                        benchmark_run_name)
+      benchmark_run.result.CopyResultsTo(benchmark_run_path)
 
   def Run(self):
     self._Run(self._experiment)
diff --git a/crosperf/perf_processor.py b/crosperf/perf_processor.py
deleted file mode 100644
index 8e6f1cd..0000000
--- a/crosperf/perf_processor.py
+++ /dev/null
@@ -1,102 +0,0 @@
-#!/usr/bin/python
-#
-# Copyright 2011 Google Inc. All Rights Reserved.
-
-import os
-import re
-
-from utils import command_executer
-
-
-class PerfProcessor(object):
-  class PerfResults(object):
-    def __init__(self, report, output):
-      self.report = report
-      self.output = output
-
-  def __init__(self, results_dir, chromeos_root, board, logger_to_use=None):
-    self._logger = logger_to_use
-    self._ce = command_executer.GetCommandExecuter(self._logger)
-    self._results_dir = results_dir
-    self._chromeos_root = chromeos_root
-    self._board = board
-    self._perf_relative_dir = os.path.basename(self._results_dir)
-    self.host_data_file = self.FindSingleFile(
-                            "perf.data", os.path.join(
-                              chromeos_root,
-                              "chroot",
-                              self._results_dir.lstrip("/")))
-    self.perf_out = self.FindSingleFile(
-                            "perf.out", os.path.join(
-                              chromeos_root,
-                              "chroot",
-                              self._results_dir.lstrip("/")))
-
-  def FindSingleFile(self, name, path):
-    find_command = ("find %s -name %s" % (path, name))
-    ret, out, err = self._ce.RunCommand(find_command, return_output=True)
-    if ret == 0:
-      data_files = out.splitlines()
-      if len(data_files) == 0:
-         # No data file, no report to generate.
-         data_file = None
-      else:
-         assert len(data_files) == 1, "More than 1 perf.out file found"
-         data_file = data_files[0]
-    return data_file
-
-
-  def GeneratePerfResults(self):
-    perf_location = os.path.join(self._results_dir,
-                                 self._perf_relative_dir)
-    if self.perf_out != None:
-      output = self._ReadPerfOutput()
-
-    if self.host_data_file != None:
-      perf_location = os.path.join(self._results_dir,
-                                   self._perf_relative_dir)
-      host_perf_location = os.path.dirname(self.host_data_file)
-      report = self._GeneratePerfReport(perf_location,
-                                        self._chromeos_root,
-                                        self._board)
-    else:
-      # lets make perf.report have output of stat...
-      report = output
-    return PerfProcessor.PerfResults(report, output)
-
-  def ParseStatResults(self, results):
-    output = results.output
-    result = {}
-    p = re.compile("\s*([0-9.]+) +(\S+)")
-    for line in output.split("\n"):
-      match = p.match(line)
-      if match:
-        result[match.group(2)] = match.group(1)
-    return result
-
-  def _ReadPerfOutput(self):
-    with open(self.perf_out, "rb") as f:
-      return f.read()
-
-  def _GeneratePerfReport(self, perf_location, chromeos_root, board):
-    perf_data_file = os.path.join(perf_location, "perf.data")
-    # Attempt to build a perf report and keep it with the results.
-    command = ("/usr/sbin/perf report --symfs=/build/%s"
-               " --vmlinux /build/%s/usr/lib/debug/boot/vmlinux"
-               " --kallsyms /build/%s/boot/System.map-*"
-               " -i %s --stdio | head -n1000" % (board, board, board,
-                                                 perf_data_file))
-    _, out, _ = self._ce.ChrootRunCommand(chromeos_root,
-                                          command, return_output=True)
-    return out
-
-
-class MockPerfProcessor(object):
-  def __init__(self):
-    pass
-
-  def GeneratePerfReport(self, *args):
-    pass
-
-  def ParseStatResults(self, *args):
-    return {}
diff --git a/crosperf/results_cache.py b/crosperf/results_cache.py
index 93a7a41..571a95b 100644
--- a/crosperf/results_cache.py
+++ b/crosperf/results_cache.py
@@ -8,6 +8,7 @@
 import os
 import pickle
 import re
+import tempfile
 
 from image_checksummer import ImageChecksummer
 from perf_processor import PerfProcessor
@@ -23,11 +24,202 @@
 
 
 class Result(object):
-  def __init__(self, out, err, retval, keyvals):
+  """ This class manages what exactly is stored inside the cache without knowing
+  what the key of the cache is. For runs with perf, it stores perf.data,
+  perf.report, etc. The key generation is handled by the ResultsCache class.
+  """
+  def __init__(self, logger):
+    self._logger = logger
+    self._ce = command_executer.GetCommandExecuter(self._logger)
+    self._temp_dir = None
+
+  def _CopyFilesTo(self, dest_dir, files_to_copy):
+    file_index = 0
+    for file_to_copy in files_to_copy:
+      if not os.path.isdir(dest_dir):
+        command = "mkdir -p %s" % dest_dir
+        self._ce.RunCommand(command)
+      dest_file = os.path.join(dest_dir,
+                               ("%s.%s" % (os.path.basename(file_to_copy),
+                                           file_index)))
+      ret = self._ce.CopyFiles(file_to_copy,
+                               dest_file,
+                               recursive=False)
+      if ret:
+        raise Exception("Could not copy results file: %s" % file_to_copy)
+
+  def CopyResultsTo(self, dest_dir):
+    self._CopyFilesTo(dest_dir, self.perf_data_files)
+    self._CopyFilesTo(dest_dir, self.perf_report_files)
+
+  def _GetKeyvals(self):
+    command = "find %s -regex .*results/keyval$" % self.results_dir
+    [ret, out, err] = self._ce.RunCommand(command, return_output=True)
+    keyvals_dict = {}
+    for f in out.splitlines():
+      keyvals = open(f, "r").read()
+      keyvals_dict.update(self._ParseKeyvals(keyvals))
+
+    return keyvals_dict
+
+  def _ParseKeyvals(self, keyvals):
+    keyval_dict = {}
+    for l in keyvals.splitlines():
+      l = l.strip()
+      if l:
+        key, val = l.split("=")
+        keyval_dict[key] = val
+    return keyval_dict
+
+  def _GetResultsDir(self):
+    mo = re.search("Results placed in (\S+)", self.out)
+    if mo:
+      result = mo.group(1)
+      return result
+    raise Exception("Could not find results directory.")
+
+  def _FindFilesInResultsDir(self, find_args):
+    command = "find %s %s" % (self.results_dir,
+                              find_args)
+    ret, out, err = self._ce.RunCommand(command, return_output=True)
+    if ret:
+      raise Exception("Could not run find command!")
+    return out
+
+  def _GetPerfDataFiles(self):
+    return self._FindFilesInResultsDir("-name perf.data").splitlines()
+
+  def _GetPerfReportFiles(self):
+    return self._FindFilesInResultsDir("-name perf.data.report").splitlines()
+
+  def _GeneratePerfReportFiles(self):
+    perf_report_files = []
+    for perf_data_file in self.perf_data_files:
+      # Generate a perf.report and store it side-by-side with the perf.data
+      # file.
+      chroot_perf_data_file = misc.GetInsideChrootPath(self._chromeos_root,
+                                                       perf_data_file)
+      perf_report_file = "%s.report" % perf_data_file
+      if os.path.exists(perf_report_file):
+        raise Exception("Perf report file already exists: %s" %
+                        perf_report_file)
+      chroot_perf_report_file = misc.GetInsideChrootPath(self._chromeos_root,
+                                                   perf_report_file)
+      command = ("/usr/sbin/perf report "
+                 "--symfs /build/%s "
+                 "-i %s --stdio "
+                 "| head -n1000 "
+                 "| tee %s" %
+                 (self._board,
+                  chroot_perf_data_file,
+                  chroot_perf_report_file))
+      ret, out, err = self._ce.ChrootRunCommand(self._chromeos_root,
+                                                command,
+                                                return_output=True)
+      # Add a keyval to the dictionary for the events captured.
+      perf_report_files.append(
+          misc.GetOutsideChrootPath(self._chromeos_root,
+                                    chroot_perf_report_file))
+    return perf_report_files
+
+  def _GatherPerfResults(self):
+    report_id = 0
+    for perf_report_file in self.perf_report_files:
+      with open(perf_report_file, "r") as f:
+        report_contents = f.read()
+        for group in re.findall("Events: (\S+) (\S+)", report_contents):
+          num_events = group[0]
+          event_name = group[1]
+          key = "perf_%s_%s" % (report_id, event_name)
+          value = str(misc.UnitToNumber(num_events))
+          self.keyvals[key] = value
+
+  def _PopulateFromRun(self, chromeos_root, board, out, err, retval):
+    self._chromeos_root = chromeos_root
+    self._board = board
     self.out = out
     self.err = err
     self.retval = retval
-    self.keyvals = keyvals
+    self.chroot_results_dir = self._GetResultsDir()
+    self.results_dir = misc.GetOutsideChrootPath(self._chromeos_root,
+                                                 self.chroot_results_dir)
+    self.perf_data_files = self._GetPerfDataFiles()
+    # Include all perf.report data in table.
+    self.perf_report_files = self._GeneratePerfReportFiles()
+    # TODO(asharif): Do something similar with perf stat.
+
+    # Grab keyvals from the directory.
+    self._ProcessResults()
+
+  def _ProcessResults(self):
+    # Note that this function doesn't know anything about whether there is a
+    # cache hit or miss. It should process results agnostic of the cache hit
+    # state.
+    self.keyvals = self._GetKeyvals()
+    self.keyvals["retval"] = self.retval
+    # Generate report from all perf.data files.
+    # Now parse all perf report files and include them in keyvals.
+    self._GatherPerfResults()
+
+  def _PopulateFromCacheDir(self, cache_dir):
+    # Read in everything from the cache directory.
+    with open(os.path.join(cache_dir, RESULTS_FILE), "r") as f:
+      self.out = pickle.load(f)
+      self.err = pickle.load(f)
+      self.retval = pickle.load(f)
+
+    # Untar the tarball to a temporary directory
+    self._temp_dir = tempfile.mkdtemp()
+    command = ("cd %s && tar xf %s" %
+               (self._temp_dir,
+                os.path.join(cache_dir, AUTOTEST_TARBALL)))
+    ret = self._ce.RunCommand(command)
+    if ret:
+      raise Exception("Could not untar cached tarball")
+    self.results_dir = self._temp_dir
+    self.perf_data_files = self._GetPerfDataFiles()
+    self.perf_report_files = self._GetPerfReportFiles()
+    self._ProcessResults()
+
+  def CleanUp(self):
+    if self._temp_dir:
+      command = "rm -rf %s" % self._temp_dir
+      self._ce.RunCommand(command)
+
+
+  def StoreToCacheDir(self, cache_dir):
+    # Create the dir if it doesn't exist.
+    command = "mkdir -p %s" % cache_dir
+    ret = self._ce.RunCommand(command)
+    if ret:
+      raise Exception("Could not create cache dir: %s" % cache_dir)
+    # Store to the cache directory.
+    with open(os.path.join(cache_dir, RESULTS_FILE), "w") as f:
+      pickle.dump(self.out, f)
+      pickle.dump(self.err, f)
+      pickle.dump(self.retval, f)
+
+    tarball = os.path.join(cache_dir, AUTOTEST_TARBALL)
+    command = ("cd %s && tar cjf %s ." % (self.results_dir, tarball))
+    ret = self._ce.RunCommand(command)
+    if ret:
+      raise Exception("Couldn't store autotest output directory.")
+
+  @classmethod
+  def CreateFromRun(cls, logger, chromeos_root, board, out, err, retval):
+    result = cls(logger)
+    result._PopulateFromRun(chromeos_root, board, out, err, retval)
+    return result
+
+  @classmethod
+  def CreateFromCacheHit(cls, logger, cache_dir):
+    result = cls(logger)
+    try:
+      result._PopulateFromCacheDir(cache_dir)
+    except Exception as e:
+      logger.LogError("Exception while using cache: %s" % e)
+      return None
+    return result
 
 
 class CacheConditions(object):
@@ -51,7 +243,11 @@
 
 
 class ResultsCache(object):
-  CACHE_VERSION = 2
+  """ This class manages the key of the cached runs without worrying about what
+  is exactly stored (value). The value generation is handled by the Results
+  class.
+  """
+  CACHE_VERSION = 3
   def Init(self, chromeos_image, chromeos_root, autotest_name, iteration,
            autotest_args, remote, board, cache_conditions,
            logger_to_use):
@@ -121,67 +317,25 @@
     if not cache_dir:
       return None
 
-    try:
-      cache_file = os.path.join(cache_dir, RESULTS_FILE)
+    if not os.path.isdir(cache_dir):
+      return None
 
-      self._logger.LogOutput("Trying to read from cache file: %s" % cache_file)
+    self._logger.LogOutput("Trying to read from cache dir: %s" % cache_dir)
 
-      with open(cache_file, "rb") as f:
-        result = pickle.load(f)
+    result = Result.CreateFromCacheHit(self._logger, cache_dir)
 
-        if (result.retval == 0 or
-            CacheConditions.RUN_SUCCEEDED not in self.cache_conditions):
-          return result
+    if not result:
+      return None
 
-    except Exception, e:
-      if CacheConditions.CACHE_FILE_EXISTS not in self.cache_conditions:
-        # Cache file not found but just return a failure.
-        return Result("", "", 1, {})
-      raise e
+    if (result.retval == 0 or
+        CacheConditions.RUN_SUCCEEDED not in self.cache_conditions):
+      return result
+
+    return None
 
   def StoreResult(self, result):
     cache_dir = self._GetCacheDirForWrite()
-    cache_file = os.path.join(cache_dir, RESULTS_FILE)
-    command = "mkdir -p %s" % cache_dir
-    ret = self._ce.RunCommand(command)
-    assert ret == 0, "Couldn't create cache dir"
-    with open(cache_file, "wb") as f:
-      pickle.dump(result, f)
-
-  def StoreAutotestOutput(self, results_dir):
-    host_results_dir = os.path.join(self.chromeos_root, "chroot",
-                                    results_dir[1:])
-    tarball = os.path.join(self._GetCacheDirForWrite(), AUTOTEST_TARBALL)
-    command = ("cd %s && tar cjf %s ." % (host_results_dir, tarball))
-    ret = self._ce.RunCommand(command)
-    if ret:
-      raise Exception("Couldn't store autotest output directory.")
-
-  def ReadAutotestOutput(self, destination):
-    cache_dir = self._GetCacheDirForRead()
-    tarball = os.path.join(cache_dir, AUTOTEST_TARBALL)
-    if not os.path.exists(tarball):
-      raise Exception("Cached autotest tarball does not exist at '%s'." %
-                      tarball)
-    command = ("cd %s && tar xjf %s ." % (destination, tarball))
-    ret = self._ce.RunCommand(command)
-    if ret:
-      raise Exception("Couldn't read autotest output directory.")
-
-  def StorePerfResults(self, perf):
-    perf_path = os.path.join(self._GetCacheDirForWrite(), PERF_RESULTS_FILE)
-    with open(perf_path, "wb") as f:
-      pickle.dump(perf.report, f)
-      pickle.dump(perf.output, f)
-
-  def ReadPerfResults(self):
-    cache_dir = self._GetCacheDirForRead()
-    perf_path = os.path.join(cache_dir, PERF_RESULTS_FILE)
-    with open(perf_path, "rb") as f:
-      report = pickle.load(f)
-      output = pickle.load(f)
-
-    return PerfProcessor.PerfResults(report, output)
+    result.StoreToCacheDir(cache_dir)
 
 
 class MockResultsCache(object):
@@ -193,15 +347,3 @@
 
   def StoreResult(self, result):
     pass
-
-  def StoreAutotestOutput(self, results_dir):
-    pass
-
-  def ReadAutotestOutput(self, destination):
-    pass
-
-  def StorePerfResults(self, perf):
-    pass
-
-  def ReadPerfResults(self):
-    return PerfProcessor.PerfResults("", "")
diff --git a/crosperf/results_sorter.py b/crosperf/results_sorter.py
index c523e10..0567ef7 100644
--- a/crosperf/results_sorter.py
+++ b/crosperf/results_sorter.py
@@ -9,7 +9,7 @@
     for benchmark_run in benchmark_runs:
       benchmark_name = benchmark_run.benchmark_name
       label_name = benchmark_run.label_name
-      for autotest_key in benchmark_run.results:
+      for autotest_key in benchmark_run.result.keyvals:
         result_tuple = (benchmark_name, autotest_key, label_name)
         if result_tuple not in self.table:
           self.table[result_tuple] = []
@@ -19,7 +19,7 @@
         while index >= len(cell):
           cell.append(None)
 
-        result_value = benchmark_run.results[autotest_key]
+        result_value = benchmark_run.result.keyvals[autotest_key]
         try:
           result_value = float(result_value)
         except ValueError:
@@ -32,7 +32,7 @@
       benchmark_name = benchmark_run.benchmark_name
       if benchmark_name not in self.autotest_keys:
         self.autotest_keys[benchmark_name] = {}
-      for autotest_key in benchmark_run.results:
+      for autotest_key in benchmark_run.result.keyvals:
         self.autotest_keys[benchmark_name][autotest_key] = True
 
   def GetAutotestKeys(self, benchmark_name):
diff --git a/crosperf/settings_factory.py b/crosperf/settings_factory.py
index 7f6ac00..95ceb0f 100644
--- a/crosperf/settings_factory.py
+++ b/crosperf/settings_factory.py
@@ -27,6 +27,7 @@
                              description="The percentage of highest/lowest "
                              "values to omit when computing the average."))
     self.AddField(ListField("profile_counters",
+                            default=["cycles"],
                             description="A list of profile counters to "
                             "collect."))
     self.AddField(EnumField("profile_type",
@@ -80,6 +81,7 @@
                             "the chromeos checkout which contains the "
                             "chromeos_image."))
     self.AddField(ListField("profile_counters",
+                            default=["cycles"],
                             description="A list of profile counters to "
                             "collect."))
     self.AddField(EnumField("profile_type",
diff --git a/utils/misc.py b/utils/misc.py
index 9111c6b..43ef09d 100644
--- a/utils/misc.py
+++ b/utils/misc.py
@@ -22,6 +22,22 @@
   return string
 
 
+def UnitToNumber(string, base=1000):
+  unit_dict = {"kilo": base,
+               "mega": base**2,
+               "giga": base**3}
+  string = string.lower()
+  mo = re.search("(\d*)(.+)", string)
+  number = mo.group(1)
+  unit = mo.group(2)
+  for k, v in unit_dict.items():
+    if k.startswith(unit):
+      return float(number) * v
+  raise Exception("Unit: %s not found in byte: %s!" %
+                  (unit,
+                   string))
+
+
 def GetFilenameFromString(string):
   return ApplySubs(string,
                    ("/", "__"),
@@ -36,6 +52,24 @@
   return (os.path.dirname(abs_path), os.path.basename(abs_path))
 
 
+def GetChrootPath(chromeos_root):
+  return os.path.join(chromeos_root,
+                      "chroot")
+
+
+def GetInsideChrootPath(chromeos_root, file_path):
+  if not file_path.startswith(GetChrootPath(chromeos_root)):
+    raise Exception("File: %s doesn't seem to be in the chroot: %s" %
+                    (file_path,
+                     chromeos_root))
+  return file_path[len(GetChrootPath(chromeos_root)):]
+
+
+def GetOutsideChrootPath(chromeos_root, file_path):
+  return os.path.join(GetChrootPath(chromeos_root),
+                      file_path.lstrip("/"))
+
+
 def FormatQuotedCommand(command):
   return ApplySubs(command,
                    ("\"", "\\\""))