def __call__(self, accumulator):
        # Outline:
        #   - Given the job and task, extend the TaskGraph to add new tasks and
        #     dependencies, being careful to filter the IDs from what we already see
        #     in the accumulator to avoid graph amendment errors.
        #   - If we do encounter graph amendment errors, we should log those and not
        #     block progress because that can only happen if there's concurrent
        #     updates being performed with the same actions.
        build_option_template = BuildOptionTemplate(
            **self.task.payload.get('build_option_template'))
        test_option_template = TestOptionTemplate(
            **self.task.payload.get('test_option_template'))

        # The ReadOptionTemplate is special because it has nested structures, so
        # we'll have to reconstitute those accordingly.
        read_option_template_map = self.task.payload.get(
            'read_option_template')
        read_option_template = ReadOptionTemplate(
            benchmark=self.task.payload.get('read_option_template').get(
                'benchmark'),
            histogram_options=read_value.HistogramOptions(
                **read_option_template_map.get('histogram_options')),
            graph_json_options=read_value.GraphJsonOptions(
                **read_option_template_map.get('graph_json_options')),
            mode=read_option_template_map.get('mode'))

        analysis_options_dict = self.task.payload.get('analysis_options')
        if self.additional_attempts:
            analysis_options_dict['min_attempts'] = min(
                analysis_options_dict.get('min_attempts', 0) +
                self.additional_attempts,
                analysis_options_dict.get('max_attempts', 100))
        analysis_options = AnalysisOptions(**analysis_options_dict)

        new_subgraph = read_value.CreateGraph(
            _CreateReadTaskOptions(build_option_template, test_option_template,
                                   read_option_template, analysis_options,
                                   self.change,
                                   self.task.payload.get('arguments', {})))
        try:
            task_module.ExtendTaskGraph(
                self.job,
                vertices=[
                    # Add all of the new vertices we do not have in the graph yet.
                    v for v in new_subgraph.vertices if v.id not in accumulator
                ],
                dependencies=[
                    # Only add dependencies to the new 'read_value' tasks.
                    task_module.Dependency(from_=self.task.id, to=v.id)
                    for v in new_subgraph.vertices if v.id not in accumulator
                    and v.vertex_type == 'read_value'
                ])
        except task_module.InvalidAmendment as e:
            logging.error('Failed to amend graph: %s', e)
 def PopulateTaskGraph(self,
                       benchmark=None,
                       chart=None,
                       grouping_label=None,
                       story=None,
                       statistic=None,
                       trace='some_trace',
                       mode='histogram_sets'):
   task_module.PopulateTaskGraph(
       self.job,
       read_value.CreateGraph(
           read_value.TaskOptions(
               test_options=run_test.TaskOptions(
                   build_options=find_isolate.TaskOptions(
                       builder='Some Builder',
                       target='telemetry_perf_tests',
                       bucket='luci.bucket',
                       change=change_module.Change.FromDict({
                           'commits': [{
                               'repository': 'chromium',
                               'git_hash': 'aaaaaaa',
                           }]
                       })),
                   swarming_server='some_server',
                   dimensions=[],
                   extra_args=[],
                   attempts=10),
               benchmark=benchmark,
               histogram_options=read_value.HistogramOptions(
                   grouping_label=grouping_label,
                   story=story,
                   statistic=statistic,
                   histogram_name=chart,
               ),
               graph_json_options=read_value.GraphJsonOptions(
                   chart=chart, trace=trace),
               mode=mode,
           )))
Example #3
0
def CreateGraph(options, arguments=None):
  if not isinstance(options, TaskOptions):
    raise ValueError(
        'options must be an instance of performance_bisection.TaskOptions')

  start_change = options.start_change
  end_change = options.end_change
  if options.pinned_change:
    start_change.Update(options.pinned_change)
    end_change.Update(options.pinned_change)

  start_change_read_options = _CreateReadTaskOptions(
      options.build_option_template, options.test_option_template,
      options.read_option_template, options.analysis_options, start_change,
      arguments if arguments else {})
  end_change_read_options = _CreateReadTaskOptions(
      options.build_option_template, options.test_option_template,
      options.read_option_template, options.analysis_options, end_change,
      arguments if arguments else {})

  # Given the start_change and end_change, we create two subgraphs that we
  # depend on from the 'find_culprit' task. This means we'll need to create
  # independent test options and build options from the template provided by the
  # caller.
  start_subgraph = read_value.CreateGraph(start_change_read_options)
  end_subgraph = read_value.CreateGraph(end_change_read_options)

  # Then we add a dependency from the 'FindCulprit' task with the payload
  # describing the options set for the performance bisection.
  find_culprit_task = task_module.TaskVertex(
      id='performance_bisection',
      vertex_type='find_culprit',
      payload={
          'start_change':
              options.start_change.AsDict(),
          'end_change':
              options.end_change.AsDict(),
          'pinned_change':
              options.pinned_change.AsDict() if options.pinned_change else None,
          # We still persist the templates, because we'll need that data in case
          # we are going to extend the graph with the same build/test templates
          # in subgraphs.
          'analysis_options':
              options.analysis_options._asdict(),
          'build_option_template':
              options.build_option_template._asdict(),
          'test_option_template':
              options.test_option_template._asdict(),
          'read_option_template': {
              'histogram_options':
                  options.read_option_template.histogram_options._asdict(),
              'graph_json_options':
                  options.read_option_template.graph_json_options._asdict(),
              'benchmark':
                  options.read_option_template.benchmark,
              'mode':
                  options.read_option_template.mode,
          },

          # Because this is a performance bisection, we'll hard-code the
          # comparison mode as 'performance'.
          'comparison_mode':
              'performance',
          'arguments':
              arguments if arguments else {},
      })
  return task_module.TaskGraph(
      vertices=list(
          itertools.chain(start_subgraph.vertices, end_subgraph.vertices)) +
      [find_culprit_task],
      edges=list(itertools.chain(start_subgraph.edges, end_subgraph.edges)) + [
          task_module.Dependency(from_=find_culprit_task.id, to=v.id)
          for v in itertools.chain(start_subgraph.vertices,
                                   end_subgraph.vertices)
          if v.vertex_type == 'read_value'
      ])