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, )))
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' ])