def main(**kwargs): the_program = programs.IO.read(kwargs['program']) subprogram_trace = {} for trace_file in kwargs['traces']: name = traces.TraceFile.extract_subprogram(the_program, trace_file) subprogram_trace[name] = trace_file for subprogram in the_program: if subprogram.name in subprogram_trace: messages.debug_message('Filtering traces for {}'.format( subprogram.name)) subprogram.cfg.dotify() ppg = graphs.ProgramPointGraph.create_from_control_flow_graph( subprogram.cfg) ppg.dotify() lnt = graphs.LoopNests(ppg) lnt.dotify() ipg = graphs.InstrumentationPointGraph.create(ppg, lnt) ipg.dotify() all_traces = filter_trace(ppg, ipg, subprogram_trace[subprogram.name]) all_traces.write(ipg.trace_filename())
def main(**kwargs): the_program = program.IO.read(kwargs['program']) the_program.call_graph.dotify() if kwargs['manual']: program.IO.read_properties(the_program, kwargs['manual']) with database.Database(kwargs['database']) as db: db.reset() for subprogram in the_program: messages.debug_message('Creating data for {}'.format(subprogram.name)) subprogram.cfg.dotify() ppg = graphs.ProgramPointGraph.create_from_control_flow_graph(subprogram.cfg) ppg.dotify() lnt = graphs.LoopNests(ppg) lnt.dotify() for v in ppg: if isinstance(v.program_point, vertices.Vertex): default = random.randint(0, kwargs['max_wcet']) else: default = 0 if kwargs['manual']: db.add_wcet(v, getattr(v.program_point, program.IO.WCET, default)) else: db.add_wcet(v, default) if lnt.is_header(v): loop = lnt.find_loop(v) if lnt.is_outermost_loop(loop): db.add_global_wfreq(v, 1) else: if kwargs['manual']: local_bound = getattr(v.program_point, program.IO.LOCAL_BOUND, random.randint(1, kwargs['max_loop_bound'])) else: local_bound = random.randint(1, kwargs['max_loop_bound']) (loop_transition,) = [predecessor_edge for predecessor_edge in lnt.predecessors(loop) if predecessor_edge.direction == edges.LoopTransition.Direction.ENTRY] if loop_transition.predecessor() == lnt.entry: db.add_local_wfreq(v, local_bound) db.add_global_wfreq(v, local_bound) else: if kwargs['manual']: global_bound = getattr(v.program_point, program.IO.GLOBAL_BOUND, random.randint(local_bound, kwargs['max_loop_bound'])) else: global_bound = random.randint(local_bound, kwargs['max_loop_bound']) db.add_local_wfreq(v, local_bound) db.add_global_wfreq(v, global_bound)
def main(**kwargs): the_program = programs.IO.read(kwargs['filename']) for subprogram in the_program: messages.debug_message('Analysing CFG for {}'.format(subprogram.name)) subprogram.cfg.dotify() ppg = graphs.ProgramPointGraph.create_from_control_flow_graph(subprogram.cfg) ppg.dotify() lnt = graphs.LoopNests(ppg) lnt.dotify() ast = graphs.SyntaxTree(ppg) ast.dotify()
def add_subprograms(the_program: program.Program, subprograms: int, loops: int, nesting_depth: int, vertices: int, fan_out: int): for subprogram_name in [ 's{}'.format(i) for i in range(1, subprograms + 1) ]: messages.debug_message( 'Creating CFG with name {}'.format(subprogram_name)) cfg = create_control_flow_graph(the_program, loops, nesting_depth, vertices, fan_out, subprogram_name) cfg.dotify() call_vertex = graph.SubprogramVertex(graph.Vertex.get_vertex_id(), subprogram_name) the_program.add_subprogram(program.Subprogram(cfg, call_vertex))
def induce(self, ppg, header, guarantee_single_exit=False): messages.debug_message('Inducing loop subgraph for header {}'.format(header)) induced_graph = ProgramPointGraph(ppg.program, ppg.name) loop = self.find_loop(header) # Add program points in the loop body. for v in loop: induced_graph.add_vertex(v) # Add edges between program points in the loop body. for v in loop: for succcessor_edge in ppg.successors(v): if succcessor_edge.successor() in induced_graph and succcessor_edge.successor() != header: induced_graph.add_edge(succcessor_edge) # Add program points and edges that model control flow out of loop. for transition_edge in self.successors(loop): if transition_edge.direction == edges.LoopTransition.Direction.EXIT: for edge in transition_edge: if edge.successor() not in induced_graph: induced_graph.add_vertex(edge.successor()) induced_graph.add_edge(edge) elif transition_edge.direction == edges.LoopTransition.Direction.ENTRY: for edge in transition_edge: if edge.successor() not in induced_graph: induced_graph.add_vertex(edge.successor()) induced_graph.add_edge(edge) # Add program points and edges that model control flow into the loop from inner loops. for transition_edge in self.predecessors(loop): if transition_edge.direction == edges.LoopTransition.Direction.EXIT: for edge in transition_edge: induced_graph.add_edge(edges.TransitionEdge(transition_edge.predecessor().header, edge.successor())) # Set the entry of the induced graph. induced_graph.entry = header if guarantee_single_exit: # Set the exit of the induced graph, if instructed. exits = [v for v in induced_graph if len(induced_graph.successors(v)) == 0] if len(exits) == 1: (induced_graph.exit,) = exits else: dummy_program_point = vertices.ProgramPointVertex(vertices.Vertex.get_vertex_id(True), vertices.Vertex(vertices.Vertex.get_vertex_id())) induced_graph.add_vertex(dummy_program_point) induced_graph.exit = dummy_program_point for exit_program_point in exits: induced_graph.add_edge(edges.TransitionEdge(exit_program_point, dummy_program_point)) return induced_graph
def main(**kwargs): kwargs['number_of_runs'] = max(kwargs['number_of_runs'], 1) the_program = program.IO.read(kwargs['program']) for subprogram in the_program: messages.debug_message('Creating traces for {}'.format(subprogram.name)) subprogram.cfg.dotify() ppg = graphs.ProgramPointGraph.create_from_control_flow_graph(subprogram.cfg) ppg.dotify() all_traces = traces.Traces() for trace_number in range(1, kwargs['number_of_runs'] + 1): trace = generate_trace(ppg, **kwargs) all_traces.append(trace) all_traces.write(ppg.trace_filename())
def add_subprograms(program: programs.Program, subprograms: int, loops: int, nesting_depth: int, dense: bool, irreducible: bool, number_of_vertices: int, fan_out: int): for subprogram_name in [ 's{}'.format(i) for i in range(1, subprograms + 1) ]: messages.debug_message( 'Creating CFG with name {}'.format(subprogram_name)) cfg = create_control_flow_graph(program, loops, nesting_depth, dense, irreducible, number_of_vertices, fan_out, subprogram_name) call_vertex = vertices.SubprogramVertex( vertices.Vertex.get_vertex_id(), subprogram_name) program.add_subprogram(programs.Subprogram(cfg, call_vertex))
def main(**kwargs): kwargs['number_of_runs'] = max(kwargs['number_of_runs'], 1) the_program = program.IO.read(kwargs['filename']) for subprogram in the_program: messages.debug_message('Creating traces for {}'.format( subprogram.name)) ppg = graph.ProgramPointGraph.create_from_control_flow_graph( subprogram.cfg) ppg.dotify() all_traces = traces.Traces() for trace_number in range(1, kwargs['number_of_runs'] + 1): trace = generate_trace(ppg, **kwargs) all_traces.append(trace) all_traces.write(ppg.trace_filename())
def inter_procedural_analysis(prog: program.Program, policy, reinstrument, traces): dfs = graphs.DepthFirstSearch(prog.call_graph, prog.call_graph.root) for call_v in dfs.post_order(): cfg = prog[call_v.name] messages.debug_message('Analysing subprogram {}'.format(cfg.name)) dot.visualise_control_flow_graph(prog, cfg) ppg = graphs.ProgramPointGraph(cfg) dot.visualise_flow_graph(prog, ppg, '.ppg') ipg = graphs.InstrumentationPointGraph.create_from_policy(ppg, policy) ipg.reduce() dot.visualise_instrumentation_point_graph(prog, ipg) prog.add_ipg(ipg) for call_e in prog.call_graph.successors(call_v): for site in call_e.call_sites: print(call_v.name, call_e.successor.name, site)
def add_subprograms(the_program: program.Program, subprograms: int, loops: int, nesting_depth: int, number_of_vertices: int, fan_out: int): for subprogram_name in ['s{}'.format(i) for i in range(1, subprograms+1)]: messages.debug_message('Creating CFG with name {}'.format(subprogram_name)) cfg = create_control_flow_graph(the_program, loops, nesting_depth, number_of_vertices, fan_out, subprogram_name) cfg.dotify() ppg = graphs.ProgramPointGraph.create_from_control_flow_graph(cfg) lnt = graphs.LoopNests(ppg) lnt.dotify() call_vertex = vertices.SubprogramVertex(vertices.Vertex.get_vertex_id(), subprogram_name) the_program.add_subprogram(program.Subprogram(cfg, call_vertex))
def inter_procedural_analysis(prog: program.Program, policy, reinstrument, traces): dfs = graph.DepthFirstSearch(prog.call_graph, prog.call_graph.root) for call_v in dfs.post_order(): cfg = prog[call_v.name] messages.debug_message('Analysing subprogram {}'.format(cfg.name)) dot.visualise_control_flow_graph(prog, cfg) ppg = graph.ProgramPointGraph(cfg) dot.visualise_flow_graph(prog, ppg, '.ppg') ipg = graph.InstrumentationPointGraph.create_from_policy(ppg, policy) ipg.reduce() dot.visualise_instrumentation_point_graph(prog, ipg) prog.add_ipg(ipg) for call_e in prog.call_graph.successors(call_v): for site in call_e.call_sites: print(call_v.name, call_e.successor.name, site)
def main(**kwargs): the_program = program.IO.read(kwargs['filename']) properties = program.IO.read_properties(kwargs['filename']) with database.Database(kwargs['database']) as db: db.reset() for subprogram in the_program: messages.debug_message('Creating data for {}'.format( subprogram.name)) ppg = graph.ProgramPointGraph.create_from_control_flow_graph( subprogram.cfg) ppg.dotify() lnt = graph.LoopNests(ppg) lnt.dotify() for v in ppg: if not kwargs[ 'manual_properties'] or v.program_point not in properties: if isinstance(v.program_point, graph.Vertex): add_automatic_wcet(db, v, kwargs['max_wcet']) else: db.add_wcet(v.program_point, 0) add_automatic_wfreq(db, v, lnt, kwargs['max_loop_bound']) else: if properties[v.program_point].wcet is not None: db.add_wcet(v.program_point, properties[v.program_point].wcet) else: add_automatic_wcet(db, v, kwargs['max_wcet']) if properties[v.program_point].bound is not None: db.add_wfreq(v.program_point, properties[v.program_point].bound) else: add_automatic_wfreq(db, v, lnt, kwargs['max_loop_bound']) if not kwargs['manual_properties']: ppg.choose_instrumentation() for v in ppg: db.set_instrumentation(v.program_point) else: for v in ppg: if v.program_point in properties: if properties[v.program_point].instrumentation: db.set_instrumentation(v.program_point)
def do_verification(cfg: graphs.ControlFlowGraph, candidate_tree, reference_tree): messages.debug_message("Verifying...") differences = set() for v in cfg: if v != cfg.entry: (candidate, ) = candidate_tree.predecessors(v) (reference, ) = reference_tree.predecessors(v) if candidate.predecessor() != reference.predecessor(): differences.add( (v, candidate.predecessor(), reference.predecessor())) message = "Differences ({} vs {}):\n{}".format( candidate_tree.__class__.__name__, reference_tree.__class__.__name__, '\n'.join('{}=>{} {}=>{}'.format(candidate, v, reference, v) for v, candidate, reference in differences)) if differences: messages.error_message(message)
def add_instructions(program: programs.Program): messages.debug_message('Adding instructions') for subprogram in program: for vertex in subprogram.cfg: if random() < 0.05: number_of_instructions = randint(10, 20) else: number_of_instructions = randint(3, 8) if len(subprogram.cfg.successors(vertex)) == 1: (edge, ) = subprogram.cfg.successors(vertex) callee = program.call_graph.is_call_site( subprogram.call_vertex, vertex) if callee: number_of_instructions -= 1 for count in range(1, number_of_instructions + 1): if len(subprogram.cfg.successors( vertex)) >= 2 and count == number_of_instructions: vertex.instructions.insert( len(vertex.instructions), instructions.BranchInstruction()) else: # Prefer arithmetic instructions over load-store instructions if random() < 0.33: population = [ instructions.LoadInstruction, instructions.StoreInstruction ] weights = [0.5, 0.5] else: population = [ instructions.AddInstruction, instructions.SubtractInstruction, instructions.MultiplyInstruction, instructions.DivideInstruction ] weights = [0.55, 0.35, 0.05, 0.05] (instruction, ) = choices(population, weights=weights) vertex.instructions.insert(0, instruction())
def cull_unreachable(self): assert self.entry # Remove edges known to be unreachable. for v in self: for e in self.successors(v): if e.direction == edges.Direction.UNREACHABLE: messages.debug_message("Edge {} is unreachable in subprogram '{}'".format(e, self.name)) self.remove_edge(e) # Remove vertices that cannot be reached from the entry vertex. dfs = DepthFirstSearch(self, self.entry) dead_vertices = [v for v in self if v not in dfs.pre_order()] for v in dead_vertices: messages.debug_message("Basic block {} is unreachable in subprogram '{}'".format(v, self.name)) self.remove_vertex(v) # Relabel edges of branches that have been flattened. for v in self: if len(self.successors(v)) == 1: (sole_e,) = self.successors(v) if sole_e.direction == edges.Direction.ELSE or sole_e.direction == edges.Direction.THEN: sole_e.direction = edges.Direction.CONTINUE
def main(**kwargs): the_program = program.IO.read(kwargs['program']) subprogram_trace = {} for trace_file in kwargs['traces']: name = traces.TraceFile.extract_subprogram(the_program, trace_file) subprogram_trace[name] = trace_file for subprogram in the_program: if subprogram.name in subprogram_trace: messages.debug_message('Filtering traces for {}'.format(subprogram.name)) subprogram.cfg.dotify() ppg = graphs.ProgramPointGraph.create_from_control_flow_graph(subprogram.cfg) ppg.dotify() lnt = graphs.LoopNests(ppg) lnt.dotify() ipg = graphs.InstrumentationPointGraph.create(ppg, lnt) ipg.dotify() all_traces = filter_trace(ppg, ipg, subprogram_trace[subprogram.name]) all_traces.write(ipg.trace_filename())
def launch_dot(ext): filename = os.path.splitext(dot_filename)[0] + '.' + ext messages.debug_message("Generating file '{}'".format(filename)) try: with open(filename, 'w') as out_file: cmd = ["dot", "-T", ext, dot_filename] p = subprocess.Popen(cmd, stdout=out_file) child_processes.append(p) _, _ = p.communicate() if p.returncode != 0: messages.error_message("Running '{}' failed".format(' '.join(cmd))) else: messages.debug_message("Done with '{}'".format(' '.join(cmd))) except FileNotFoundError as e: messages.debug_message(e)
def launch_dot(ext): filename = os.path.splitext(dot_filename)[0] + '.' + ext messages.debug_message("Generating file '{}'".format(filename)) try: with open(filename, 'w') as out_file: cmd = ["dot", "-T", ext, dot_filename] p = subprocess.Popen(cmd, stdout=out_file) child_processes.append(p) _, _ = p.communicate() if p.returncode != 0: messages.error_message("Running '{}' failed".format( ' '.join(cmd))) else: messages.debug_message("Done with '{}'".format( ' '.join(cmd))) except FileNotFoundError as e: messages.debug_message(e)
def read(cls, filename: str) -> Program: messages.debug_message("Reading program from '{}'".format(filename)) program = Program(filename) cfgs = [] calls = [] with open(filename) as json_file: program_json = json.load(json_file) magic_info = program_json[0] program.magic = magic_info[1] subprograms_json = program_json[1] for subprogram_name, (vertices_json, edges_json) in subprograms_json.items(): cfg = graphs.ControlFlowGraph(program, subprogram_name) cfgs.append(cfg) for vertex_json in vertices_json: vertex_id = int(vertex_json[0]) vertex = vertices.BasicBlock(int(vertex_id)) cfg.add_vertex(vertex) instruction_json = vertex_json[1] for instruction_text in instruction_json: if instruction_text[ 0] == instructions.CallInstruction.OPCODE: callee = instruction_text[1] calls.append([cfg.name, callee, vertex]) vertex.instructions.append( instructions.CallInstruction(callee)) elif instruction_text[ 0] == instructions.BranchInstruction.OPCODE: vertex.instructions.append( instructions.BranchInstruction()) elif instruction_text[ 0] == instructions.StoreInstruction.OPCODE: vertex.instructions.append( instructions.StoreInstruction()) elif instruction_text[ 0] == instructions.LoadInstruction.OPCODE: vertex.instructions.append( instructions.LoadInstruction()) elif instruction_text[ 0] == instructions.AddInstruction.OPCODE: vertex.instructions.append( instructions.AddInstruction()) elif instruction_text[ 0] == instructions.SubtractInstruction.OPCODE: vertex.instructions.append( instructions.SubtractInstruction()) elif instruction_text[ 0] == instructions.MultiplyInstruction.OPCODE: vertex.instructions.append( instructions.MultiplyInstruction()) elif instruction_text[ 0] == instructions.DivideInstruction.OPCODE: vertex.instructions.append( instructions.DivideInstruction()) for edge_json in edges_json: predecessor_id, successor_id = edge_json predecessor = vertices.Vertex.id_pool[int(predecessor_id)] successor = vertices.Vertex.id_pool[int(successor_id)] cfg.add_edge(edges.ControlFlowEdge(predecessor, successor)) for cfg in cfgs: call = vertices.SubprogramVertex(vertices.Vertex.get_vertex_id(), cfg.name) subprogram = Subprogram(cfg, call) program.add_subprogram(subprogram) for vertex in cfg: if len(cfg.predecessors(vertex)) == 0: assert cfg.entry is None cfg.entry = vertex if len(cfg.successors(vertex)) == 0: assert cfg.exit is None cfg.exit = vertex cfg.add_edge(edges.ControlFlowEdge(cfg.exit, cfg.entry)) for caller, callee, site in calls: caller = program[caller].call_vertex callee = program[callee].call_vertex program.call_graph.add_edge( edges.CallGraphEdge(caller, callee, site)) return program
def main(program_filename: str, repeat: int, subprogram_names: typing.List[str], verify: bool): the_program = programs.IO.read(program_filename) the_program.cleanup() messages.verbose_message( "Verification is {}".format("ON" if verify else "OFF")) analysable_subprograms = [ subprogram for subprogram in the_program if not subprogram_names or ( subprogram_names and subprogram.name in subprogram_names) ] results = [] speedups = [] slowdowns = [] for subprogram in analysable_subprograms: messages.verbose_message("Analysing", subprogram.name) subprogram.cfg.dotify() betts_times = [] tarjan_times = [] cooper_times = [] for i in range(0, repeat): subprogram.cfg.shuffle_edges() start = time.time() betts_tree = graphs.Betts(subprogram.cfg) betts_times.append(time.time() - start) start = time.time() tarjan_tree = graphs.LengauerTarjan(subprogram.cfg, subprogram.cfg.entry) tarjan_times.append(time.time() - start) start = time.time() cooper_tree = graphs.Cooper(subprogram.cfg) cooper_times.append(time.time() - start) if verify: messages.debug_message("Betts versus Tarjan") do_verification(subprogram.cfg, betts_tree, tarjan_tree) messages.debug_message("Cooper versus Tarjan") do_verification(subprogram.cfg, cooper_tree, tarjan_tree) messages.debug_message("Betts versus Cooper") do_verification(subprogram.cfg, betts_tree, cooper_tree) betts = Time(Algorithms.Betts, sum(betts_times) / repeat) cooper = Time(Algorithms.Cooper, sum(cooper_times) / repeat) tarjan = Time(Algorithms.Tarjan, sum(tarjan_times) / repeat) times = [betts, cooper, tarjan] times.sort(key=lambda t: t.time) results.append(times) messages.verbose_message( '{} vertices={} edges={} branches={} merges={}'.format( subprogram.name, subprogram.cfg.number_of_vertices(), subprogram.cfg.number_of_edges(), subprogram.cfg.number_of_branches(), subprogram.cfg.number_of_merges())) messages.verbose_message('{}:: {:.4f}'.format(times[0].name.value, times[0].time)) messages.verbose_message('{}:: {:.4f} {:.1f}X faster'.format( times[1].name.value, times[1].time, times[1].time / times[0].time)) messages.verbose_message('{}:: {:.4f} {:.1f}X faster'.format( times[2].name.value, times[2].time, times[2].time / times[0].time)) messages.verbose_message("======> Summary") for name in Algorithms: first = [r for r in results if r[0].name == name] if first: messages.verbose_message('{} came first {} times'.format( name.value, len(first))) for name in Algorithms: second = [r for r in results if r[1].name == name] if second: messages.verbose_message('{} came second {} times'.format( name.value, len(second))) for name in Algorithms: third = [r for r in results if r[2].name == name] if third: messages.verbose_message('{} came third {} times'.format( name.value, len(third)))
def main(**kwargs): the_program = programs.IO.read(kwargs['program']) the_program.call_graph.dotify() if kwargs['manual']: programs.IO.read_properties(the_program, kwargs['manual']) with database.Database(kwargs['database']) as db: db.reset() for subprogram in the_program: messages.debug_message('Creating data for {}'.format( subprogram.name)) subprogram.cfg.dotify() ppg = graphs.ProgramPointGraph.create_from_control_flow_graph( subprogram.cfg) ppg.dotify() lnt = graphs.LoopNests(ppg) lnt.dotify() for v in ppg: if isinstance(v.program_point, vertices.Vertex): default = random.randint(0, kwargs['max_wcet']) else: default = 0 if kwargs['manual']: db.add_wcet( v, getattr(v.program_point, programs.IO.WCET, default)) else: db.add_wcet(v, default) if lnt.is_header(v): loop = lnt.find_loop(v) if lnt.is_outermost_loop(loop): db.add_global_wfreq(v, 1) else: if kwargs['manual']: local_bound = getattr( v.program_point, programs.IO.LOCAL_BOUND, random.randint(1, kwargs['max_loop_bound'])) else: local_bound = random.randint( 1, kwargs['max_loop_bound']) (loop_transition, ) = [ predecessor_edge for predecessor_edge in lnt.predecessors(loop) if predecessor_edge.direction == edges.LoopTransition.Direction.ENTRY ] if loop_transition.predecessor() == lnt.entry: db.add_local_wfreq(v, local_bound) db.add_global_wfreq(v, local_bound) else: if kwargs['manual']: global_bound = getattr( v.program_point, programs.IO.GLOBAL_BOUND, random.randint(local_bound, kwargs['max_loop_bound'])) else: global_bound = random.randint( local_bound, kwargs['max_loop_bound']) db.add_local_wfreq(v, local_bound) db.add_global_wfreq(v, global_bound)