aboutsummaryrefslogtreecommitdiff
path: root/crosperf/experiment_file.py
diff options
context:
space:
mode:
Diffstat (limited to 'crosperf/experiment_file.py')
-rw-r--r--crosperf/experiment_file.py415
1 files changed, 218 insertions, 197 deletions
diff --git a/crosperf/experiment_file.py b/crosperf/experiment_file.py
index d2831bda..70852a22 100644
--- a/crosperf/experiment_file.py
+++ b/crosperf/experiment_file.py
@@ -1,220 +1,241 @@
# -*- coding: utf-8 -*-
-# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
+# Copyright 2011 The ChromiumOS Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""The experiment file module. It manages the input file of crosperf."""
-from __future__ import print_function
+
import os.path
import re
+
from settings_factory import SettingsFactory
class ExperimentFile(object):
- """Class for parsing the experiment file format.
+ """Class for parsing the experiment file format.
- The grammar for this format is:
+ The grammar for this format is:
- experiment = { _FIELD_VALUE_RE | settings }
- settings = _OPEN_SETTINGS_RE
- { _FIELD_VALUE_RE }
- _CLOSE_SETTINGS_RE
+ experiment = { _FIELD_VALUE_RE | settings }
+ settings = _OPEN_SETTINGS_RE
+ { _FIELD_VALUE_RE }
+ _CLOSE_SETTINGS_RE
- Where the regexes are terminals defined below. This results in an format
- which looks something like:
+ Where the regexes are terminals defined below. This results in an format
+ which looks something like:
- field_name: value
- settings_type: settings_name {
- field_name: value
field_name: value
- }
- """
-
- # Field regex, e.g. "iterations: 3"
- _FIELD_VALUE_RE = re.compile(r'(\+)?\s*(\w+?)(?:\.(\S+))?\s*:\s*(.*)')
- # Open settings regex, e.g. "label {"
- _OPEN_SETTINGS_RE = re.compile(r'(?:([\w.-]+):)?\s*([\w.-]+)\s*{')
- # Close settings regex.
- _CLOSE_SETTINGS_RE = re.compile(r'}')
-
- def __init__(self, experiment_file, overrides=None):
- """Construct object from file-like experiment_file.
-
- Args:
- experiment_file: file-like object with text description of experiment.
- overrides: A settings object that will override fields in other settings.
-
- Raises:
- Exception: if invalid build type or description is invalid.
+ settings_type: settings_name {
+ field_name: value
+ field_name: value
+ }
"""
- self.all_settings = []
- self.global_settings = SettingsFactory().GetSettings('global', 'global')
- self.all_settings.append(self.global_settings)
-
- self._Parse(experiment_file)
-
- for settings in self.all_settings:
- settings.Inherit()
- settings.Validate()
- if overrides:
- settings.Override(overrides)
-
- def GetSettings(self, settings_type):
- """Return nested fields from the experiment file."""
- res = []
- for settings in self.all_settings:
- if settings.settings_type == settings_type:
- res.append(settings)
- return res
-
- def GetGlobalSettings(self):
- """Return the global fields from the experiment file."""
- return self.global_settings
-
- def _ParseField(self, reader):
- """Parse a key/value field."""
- line = reader.CurrentLine().strip()
- match = ExperimentFile._FIELD_VALUE_RE.match(line)
- append, name, _, text_value = match.groups()
- return (name, text_value, append)
-
- def _ParseSettings(self, reader):
- """Parse a settings block."""
- line = reader.CurrentLine().strip()
- match = ExperimentFile._OPEN_SETTINGS_RE.match(line)
- settings_type = match.group(1)
- if settings_type is None:
- settings_type = ''
- settings_name = match.group(2)
- settings = SettingsFactory().GetSettings(settings_name, settings_type)
- settings.SetParentSettings(self.global_settings)
-
- while reader.NextLine():
- line = reader.CurrentLine().strip()
-
- if not line:
- continue
-
- if ExperimentFile._FIELD_VALUE_RE.match(line):
- field = self._ParseField(reader)
- settings.SetField(field[0], field[1], field[2])
- elif ExperimentFile._CLOSE_SETTINGS_RE.match(line):
- return settings, settings_type
-
- raise EOFError('Unexpected EOF while parsing settings block.')
-
- def _Parse(self, experiment_file):
- """Parse experiment file and create settings."""
- reader = ExperimentFileReader(experiment_file)
- settings_names = {}
- try:
- while reader.NextLine():
+
+ # Field regex, e.g. "iterations: 3"
+ _FIELD_VALUE_RE = re.compile(r"(\+)?\s*(\w+?)(?:\.(\S+))?\s*:\s*(.*)")
+ # Open settings regex, e.g. "label {"
+ _OPEN_SETTINGS_RE = re.compile(r"(?:([\w.-]+):)?\s*([\w.-]+)\s*{")
+ # Close settings regex.
+ _CLOSE_SETTINGS_RE = re.compile(r"}")
+
+ def __init__(self, experiment_file, overrides=None):
+ """Construct object from file-like experiment_file.
+
+ Args:
+ experiment_file: file-like object with text description of experiment.
+ overrides: A settings object that will override fields in other settings.
+
+ Raises:
+ Exception: if invalid build type or description is invalid.
+ """
+ self.all_settings = []
+ self.global_settings = SettingsFactory().GetSettings("global", "global")
+ self.all_settings.append(self.global_settings)
+
+ self._Parse(experiment_file)
+
+ for settings in self.all_settings:
+ settings.Inherit()
+ settings.Validate()
+ if overrides:
+ settings.Override(overrides)
+
+ def GetSettings(self, settings_type):
+ """Return nested fields from the experiment file."""
+ res = []
+ for settings in self.all_settings:
+ if settings.settings_type == settings_type:
+ res.append(settings)
+ return res
+
+ def GetGlobalSettings(self):
+ """Return the global fields from the experiment file."""
+ return self.global_settings
+
+ def _ParseField(self, reader):
+ """Parse a key/value field."""
line = reader.CurrentLine().strip()
+ match = ExperimentFile._FIELD_VALUE_RE.match(line)
+ append, name, _, text_value = match.groups()
+ return (name, text_value, append)
- if not line:
- continue
-
- if ExperimentFile._OPEN_SETTINGS_RE.match(line):
- new_settings, settings_type = self._ParseSettings(reader)
- # We will allow benchmarks with duplicated settings name for now.
- # Further decision will be made when parsing benchmark details in
- # ExperimentFactory.GetExperiment().
- if settings_type != 'benchmark':
- if new_settings.name in settings_names:
- raise SyntaxError(
- "Duplicate settings name: '%s'." % new_settings.name)
- settings_names[new_settings.name] = True
- self.all_settings.append(new_settings)
- elif ExperimentFile._FIELD_VALUE_RE.match(line):
- field = self._ParseField(reader)
- self.global_settings.SetField(field[0], field[1], field[2])
- else:
- raise IOError('Unexpected line.')
- except Exception as err:
- raise RuntimeError('Line %d: %s\n==> %s' % (reader.LineNo(), str(err),
- reader.CurrentLine(False)))
-
- def Canonicalize(self):
- """Convert parsed experiment file back into an experiment file."""
- res = ''
- board = ''
- for field_name in self.global_settings.fields:
- field = self.global_settings.fields[field_name]
- if field.assigned:
- res += '%s: %s\n' % (field.name, field.GetString())
- if field.name == 'board':
- board = field.GetString()
- res += '\n'
-
- for settings in self.all_settings:
- if settings.settings_type != 'global':
- res += '%s: %s {\n' % (settings.settings_type, settings.name)
- for field_name in settings.fields:
- field = settings.fields[field_name]
- if field.assigned:
- res += '\t%s: %s\n' % (field.name, field.GetString())
- if field.name == 'chromeos_image':
- real_file = (
- os.path.realpath(os.path.expanduser(field.GetString())))
- if real_file != field.GetString():
- res += '\t#actual_image: %s\n' % real_file
- if field.name == 'build':
- chromeos_root_field = settings.fields['chromeos_root']
- if chromeos_root_field:
- chromeos_root = chromeos_root_field.GetString()
- value = field.GetString()
- autotest_field = settings.fields['autotest_path']
- autotest_path = ''
- if autotest_field.assigned:
- autotest_path = autotest_field.GetString()
- debug_field = settings.fields['debug_path']
- debug_path = ''
- if debug_field.assigned:
- debug_path = autotest_field.GetString()
- # Do not download the debug symbols since this function is for
- # canonicalizing experiment file.
- downlad_debug = False
- image_path, autotest_path, debug_path = settings.GetXbuddyPath(
- value, autotest_path, debug_path, board, chromeos_root,
- 'quiet', downlad_debug)
- res += '\t#actual_image: %s\n' % image_path
- if not autotest_field.assigned:
- res += '\t#actual_autotest_path: %s\n' % autotest_path
- if not debug_field.assigned:
- res += '\t#actual_debug_path: %s\n' % debug_path
-
- res += '}\n\n'
-
- return res
+ def _ParseSettings(self, reader):
+ """Parse a settings block."""
+ line = reader.CurrentLine().strip()
+ match = ExperimentFile._OPEN_SETTINGS_RE.match(line)
+ settings_type = match.group(1)
+ if settings_type is None:
+ settings_type = ""
+ settings_name = match.group(2)
+ settings = SettingsFactory().GetSettings(settings_name, settings_type)
+ settings.SetParentSettings(self.global_settings)
+
+ while reader.NextLine():
+ line = reader.CurrentLine().strip()
+
+ if not line:
+ continue
+
+ if ExperimentFile._FIELD_VALUE_RE.match(line):
+ field = self._ParseField(reader)
+ settings.SetField(field[0], field[1], field[2])
+ elif ExperimentFile._CLOSE_SETTINGS_RE.match(line):
+ return settings, settings_type
+
+ raise EOFError("Unexpected EOF while parsing settings block.")
+
+ def _Parse(self, experiment_file):
+ """Parse experiment file and create settings."""
+ reader = ExperimentFileReader(experiment_file)
+ settings_names = {}
+ try:
+ while reader.NextLine():
+ line = reader.CurrentLine().strip()
+
+ if not line:
+ continue
+
+ if ExperimentFile._OPEN_SETTINGS_RE.match(line):
+ new_settings, settings_type = self._ParseSettings(reader)
+ # We will allow benchmarks with duplicated settings name for now.
+ # Further decision will be made when parsing benchmark details in
+ # ExperimentFactory.GetExperiment().
+ if settings_type != "benchmark":
+ if new_settings.name in settings_names:
+ raise SyntaxError(
+ "Duplicate settings name: '%s'."
+ % new_settings.name
+ )
+ settings_names[new_settings.name] = True
+ self.all_settings.append(new_settings)
+ elif ExperimentFile._FIELD_VALUE_RE.match(line):
+ field = self._ParseField(reader)
+ self.global_settings.SetField(field[0], field[1], field[2])
+ else:
+ raise IOError("Unexpected line.")
+ except Exception as err:
+ raise RuntimeError(
+ "Line %d: %s\n==> %s"
+ % (reader.LineNo(), str(err), reader.CurrentLine(False))
+ )
+
+ def Canonicalize(self):
+ """Convert parsed experiment file back into an experiment file."""
+ res = ""
+ board = ""
+ for field_name in self.global_settings.fields:
+ field = self.global_settings.fields[field_name]
+ if field.assigned:
+ res += "%s: %s\n" % (field.name, field.GetString())
+ if field.name == "board":
+ board = field.GetString()
+ res += "\n"
+
+ for settings in self.all_settings:
+ if settings.settings_type != "global":
+ res += "%s: %s {\n" % (settings.settings_type, settings.name)
+ for field_name in settings.fields:
+ field = settings.fields[field_name]
+ if field.assigned:
+ res += "\t%s: %s\n" % (field.name, field.GetString())
+ if field.name == "chromeos_image":
+ real_file = os.path.realpath(
+ os.path.expanduser(field.GetString())
+ )
+ if real_file != field.GetString():
+ res += "\t#actual_image: %s\n" % real_file
+ if field.name == "build":
+ chromeos_root_field = settings.fields[
+ "chromeos_root"
+ ]
+ if chromeos_root_field:
+ chromeos_root = chromeos_root_field.GetString()
+ value = field.GetString()
+ autotest_field = settings.fields["autotest_path"]
+ autotest_path = ""
+ if autotest_field.assigned:
+ autotest_path = autotest_field.GetString()
+ debug_field = settings.fields["debug_path"]
+ debug_path = ""
+ if debug_field.assigned:
+ debug_path = autotest_field.GetString()
+ # Do not download the debug symbols since this function is for
+ # canonicalizing experiment file.
+ downlad_debug = False
+ (
+ image_path,
+ autotest_path,
+ debug_path,
+ ) = settings.GetXbuddyPath(
+ value,
+ autotest_path,
+ debug_path,
+ board,
+ chromeos_root,
+ "quiet",
+ downlad_debug,
+ )
+ res += "\t#actual_image: %s\n" % image_path
+ if not autotest_field.assigned:
+ res += (
+ "\t#actual_autotest_path: %s\n"
+ % autotest_path
+ )
+ if not debug_field.assigned:
+ res += "\t#actual_debug_path: %s\n" % debug_path
+
+ res += "}\n\n"
+
+ return res
class ExperimentFileReader(object):
- """Handle reading lines from an experiment file."""
-
- def __init__(self, file_object):
- self.file_object = file_object
- self.current_line = None
- self.current_line_no = 0
-
- def CurrentLine(self, strip_comment=True):
- """Return the next line from the file, without advancing the iterator."""
- if strip_comment:
- return self._StripComment(self.current_line)
- return self.current_line
-
- def NextLine(self, strip_comment=True):
- """Advance the iterator and return the next line of the file."""
- self.current_line_no += 1
- self.current_line = self.file_object.readline()
- return self.CurrentLine(strip_comment)
-
- def _StripComment(self, line):
- """Strip comments starting with # from a line."""
- if '#' in line:
- line = line[:line.find('#')] + line[-1]
- return line
-
- def LineNo(self):
- """Return the current line number."""
- return self.current_line_no
+ """Handle reading lines from an experiment file."""
+
+ def __init__(self, file_object):
+ self.file_object = file_object
+ self.current_line = None
+ self.current_line_no = 0
+
+ def CurrentLine(self, strip_comment=True):
+ """Return the next line from the file, without advancing the iterator."""
+ if strip_comment:
+ return self._StripComment(self.current_line)
+ return self.current_line
+
+ def NextLine(self, strip_comment=True):
+ """Advance the iterator and return the next line of the file."""
+ self.current_line_no += 1
+ self.current_line = self.file_object.readline()
+ return self.CurrentLine(strip_comment)
+
+ def _StripComment(self, line):
+ """Strip comments starting with # from a line."""
+ if "#" in line:
+ line = line[: line.find("#")] + line[-1]
+ return line
+
+ def LineNo(self):
+ """Return the current line number."""
+ return self.current_line_no