def run(self, func_or_src, args=[], import_site=False, **jitopts): jitopts.setdefault('threshold', 200) src = py.code.Source(func_or_src) if isinstance(func_or_src, types.FunctionType): funcname = func_or_src.func_name else: funcname = 'main' # write the snippet arglist = ', '.join(map(repr, args)) with self.filepath.open("w") as f: # we don't want to see the small bridges created # by the checkinterval reaching the limit f.write("import sys\n") f.write("sys.setcheckinterval(10000000)\n") f.write(str(src) + "\n") f.write("print %s(%s)\n" % (funcname, arglist)) # # run a child pypy-c with logging enabled logfile = self.filepath.new(ext='.log') # cmdline = [sys.executable] if not import_site: cmdline.append('-S') if jitopts: jitcmdline = ['%s=%s' % (key, value) for key, value in jitopts.items()] cmdline += ['--jit', ','.join(jitcmdline)] cmdline.append(str(self.filepath)) # env = os.environ.copy() env['PYPYLOG'] = self.log_string + ':' + str(logfile) pipe = subprocess.Popen(cmdline, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = pipe.communicate() if getattr(pipe, 'returncode', 0) < 0: raise IOError("subprocess was killed by signal %d" % ( pipe.returncode,)) if stderr.startswith('SKIP:'): py.test.skip(stderr) if stderr.startswith('debug_alloc.h:'): # lldebug builds stderr = '' assert not stderr # # parse the JIT log rawlog = logparser.parse_log_file(str(logfile)) rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = eval(stdout) log.logfile = str(logfile) # summaries = logparser.extract_category(rawlog, 'jit-summary') if len(summaries) > 0: log.jit_summary = parse_prof(summaries[-1]) else: log.jit_summary = None # return log
def import_log(logname, ParserCls=SimpleParser): log = parse_log_file(logname) hex_re = '0x(-?[\da-f]+)' addrs = {} for entry in extract_category(log, 'jit-backend-addr'): m = re.search('bootstrap ' + hex_re, entry) if not m: # a bridge m = re.search('has address ' + hex_re, entry) addr = int(m.group(1), 16) entry = entry.lower() m = re.search('guard ' + hex_re, entry) name = 'guard ' + m.group(1) else: name = entry[:entry.find('(') - 1].lower() addr = int(m.group(1), 16) addrs.setdefault(addr, []).append(name) from rpython.jit.backend.tool.viewcode import World world = World() for entry in extract_category(log, 'jit-backend-dump'): world.parse(entry.splitlines(True)) dumps = {} for r in world.ranges: if r.addr in addrs and addrs[r.addr]: name = addrs[r.addr].pop(0) # they should come in order data = r.data.encode('hex') # backward compatibility dumps[name] = (world.backend_name, r.addr, data) loops = [] cat = extract_category(log, 'jit-log-opt') if not cat: cat = extract_category(log, 'jit-log-rewritten') if not cat: cat = extract_category(log, 'jit-log-noopt') for entry in cat: parser = ParserCls(entry, None, {}, 'lltype', None, nonstrict=True) loop = parser.parse() comm = loop.comment comm = comm.lower() if comm.startswith('# bridge'): m = re.search('guard 0x(-?[\da-f]+)', comm) name = 'guard ' + m.group(1) elif "(" in comm: name = comm[2:comm.find('(') - 1] else: name = " ".join(comm[2:].split(" ", 2)[:2]) if name in dumps: bname, start_ofs, dump = dumps[name] loop.force_asm = ( lambda dump=dump, start_ofs=start_ofs, bname=bname, loop=loop: parser.postprocess(loop, backend_tp=bname, backend_dump=dump, dump_start=start_ofs)) loops += split_trace(loop) return log, loops
def import_log(logname, ParserCls=SimpleParser): log = parse_log_file(logname) hex_re = '0x(-?[\da-f]+)' addrs = {} for entry in extract_category(log, 'jit-backend-addr'): m = re.search('bootstrap ' + hex_re, entry) if not m: # a bridge m = re.search('has address ' + hex_re, entry) addr = int(m.group(1), 16) entry = entry.lower() m = re.search('guard ' + hex_re, entry) name = 'guard ' + m.group(1) else: name = entry[:entry.find('(') - 1].lower() addr = int(m.group(1), 16) addrs.setdefault(addr, []).append(name) from rpython.jit.backend.tool.viewcode import World world = World() for entry in extract_category(log, 'jit-backend-dump'): world.parse(entry.splitlines(True)) dumps = {} for r in world.ranges: if r.addr in addrs and addrs[r.addr]: name = addrs[r.addr].pop(0) # they should come in order data = r.data.encode('hex') # backward compatibility dumps[name] = (world.backend_name, r.addr, data) loops = [] cat = extract_category(log, 'jit-log-opt') if not cat: cat = extract_category(log, 'jit-log-rewritten') if not cat: cat = extract_category(log, 'jit-log-noopt') for entry in cat: parser = ParserCls(entry, None, {}, 'lltype', None, nonstrict=True) loop = parser.parse() comm = loop.comment comm = comm.lower() if comm.startswith('# bridge'): m = re.search('guard 0x(-?[\da-f]+)', comm) name = 'guard ' + m.group(1) elif "(" in comm: name = comm[2:comm.find('(')-1] else: name = " ".join(comm[2:].split(" ", 2)[:2]) if name in dumps: bname, start_ofs, dump = dumps[name] loop.force_asm = (lambda dump=dump, start_ofs=start_ofs, bname=bname, loop=loop: parser.postprocess(loop, backend_tp=bname, backend_dump=dump, dump_start=start_ofs)) loops += split_trace(loop) return log, loops
def test_really_run(): """ This test checks whether output of jitprof did not change. It'll explode when someone touches jitprof.py """ mydriver = JitDriver(reds = ['i', 'n'], greens = []) def f(n): i = 0 while i < n: mydriver.can_enter_jit(i=i, n=n) mydriver.jit_merge_point(i=i, n=n) i += 1 cap = py.io.StdCaptureFD() try: ll_meta_interp(f, [10], CPUClass=runner.LLGraphCPU, type_system='lltype', ProfilerClass=Profiler) finally: out, err = cap.reset() log = parse_log(err.splitlines(True)) err_sections = list(extract_category(log, 'jit-summary')) [err1] = err_sections # there should be exactly one jit-summary assert err1.count("\n") == JITPROF_LINES info = parse_prof(err1) # assert did not crash # asserts below are a bit delicate, possibly they might be deleted assert info.tracing_no == 1 assert info.backend_no == 1 assert info.ops.total == 2 assert info.recorded_ops.total == 2 assert info.recorded_ops.calls == 0 assert info.guards == 2 assert info.opt_ops == 13 assert info.opt_guards == 2 assert info.forcings == 0
def test_really_run(): """ This test checks whether output of jitprof did not change. It'll explode when someone touches jitprof.py """ mydriver = JitDriver(reds = ['i', 'n'], greens = []) def f(n): i = 0 while i < n: mydriver.can_enter_jit(i=i, n=n) mydriver.jit_merge_point(i=i, n=n) i += 1 cap = py.io.StdCaptureFD() try: ll_meta_interp(f, [10], CPUClass=runner.LLGraphCPU, ProfilerClass=Profiler) finally: out, err = cap.reset() log = parse_log(err.splitlines(True)) err_sections = list(extract_category(log, 'jit-summary')) [err1] = err_sections # there should be exactly one jit-summary assert err1.count("\n") == JITPROF_LINES info = parse_prof(err1) # assert did not crash # asserts below are a bit delicate, possibly they might be deleted assert info.tracing_no == 1 assert info.backend_no == 1 assert info.ops.total == 2 assert info.recorded_ops.total == 2 assert info.recorded_ops.calls == 0 assert info.guards == 2 assert info.opt_ops == 11 assert info.opt_guards == 2 assert info.forcings == 0
def run(self, src, call, **jitopts): jitopts.setdefault('threshold', 200) # write the snippet with self.filepath.open("w") as f: # we don't want to see the small bridges created # by the checkinterval reaching the limit f.write(str(src) + "\n") # # run a child pyrolog-c with logging enabled logfile = self.filepath.new(ext='.log') # cmdline = [strexecutable] cmdline.append(str(self.filepath)) # print cmdline, logfile env = {'PYPYLOG': 'jit-log-opt,jit-summary:' + str(logfile)} #env={'PYPYLOG': ':' + str(logfile)} pipe = subprocess.Popen(cmdline, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) pipe.stdin.write(call + "\n") stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) if stderr.startswith('debug_alloc.h:'): # lldebug builds stderr = '' assert not stderr # # parse the JIT log rawlog = logparser.parse_log_file(str(logfile)) rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = stdout if "ParseError" in log.result or "ERROR" in log.result: assert 0, log.result # summaries = logparser.extract_category(rawlog, 'jit-summary') if len(summaries) > 0: log.jit_summary = parse_prof(summaries[-1]) else: log.jit_summary = None # return log
def run(self, src, call, **jitopts): jitopts.setdefault('threshold', 200) # write the snippet with self.filepath.open("w") as f: # we don't want to see the small bridges created # by the checkinterval reaching the limit f.write(str(src) + "\n") # # run a child pyrolog-c with logging enabled logfile = self.filepath.new(ext='.log') # cmdline = [strexecutable] cmdline.append(str(self.filepath)) # print cmdline, logfile env={'PYPYLOG': 'jit-log-opt,jit-summary:' + str(logfile)} #env={'PYPYLOG': ':' + str(logfile)} pipe = subprocess.Popen(cmdline, env=env, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) pipe.stdin.write(call + "\n") stdout, stderr = pipe.communicate() if stderr.startswith('SKIP:'): py.test.skip(stderr) if stderr.startswith('debug_alloc.h:'): # lldebug builds stderr = '' assert not stderr # # parse the JIT log rawlog = logparser.parse_log_file(str(logfile)) rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = stdout if "ParseError" in log.result or "ERROR" in log.result: assert 0, log.result # summaries = logparser.extract_category(rawlog, 'jit-summary') if len(summaries) > 0: log.jit_summary = parse_prof(summaries[-1]) else: log.jit_summary = None # return log
def main(progname, logfilename, outfilename): storage = LoopStorage(extrapath=os.path.dirname(progname)) log, loops = import_log(logfilename) parse_log_counts(extract_category(log, 'jit-backend-count'), loops) storage.loops = [loop for loop in loops if not loop.descr.startswith('bridge')] storage.loop_dict = create_loop_dict(loops) json.dump([loop.force_asm().as_json() for loop in storage.loops], open(outfilename, "w"), indent=4)
def main(progname, logfilename, outfilename): storage = LoopStorage(extrapath=os.path.dirname(progname)) log, loops = import_log(logfilename) parse_log_counts(extract_category(log, 'jit-backend-count'), loops) storage.loops = [ loop for loop in loops if not loop.descr.startswith('bridge') ] storage.loop_dict = create_loop_dict(loops) json.dump([loop.force_asm().as_json() for loop in storage.loops], open(outfilename, "w"), indent=4)
def consider_category(log, options, category): loops = logparser.extract_category(log, category) if options.loopnum is None: input_loops = loops else: input_loops = [loops[options.loopnum]] loops = [parse(inp, no_namespace=True, nonstrict=True) for inp in input_loops] summary = {} for loop in loops: summary = loop.summary(summary) return loops, summary
def consider_category(log, options, category): loops = logparser.extract_category(log, category) if options.loopnum is None: input_loops = loops else: input_loops = [loops[options.loopnum]] loops = [ parse(inp, no_namespace=True, nonstrict=True) for inp in input_loops ] summary = {} for loop in loops: summary = loop.summary(summary) return loops, summary
def run(self, topaz, tmpdir, code): tmpdir.join("t.rb").write(code) proc = subprocess.Popen( [str(topaz), str(tmpdir.join("t.rb"))], cwd=str(tmpdir), env={"PYPYLOG": "jit-log-opt:%s" % tmpdir.join("x.pypylog")}) proc.wait() data = logparser.parse_log_file(str(tmpdir.join("x.pypylog")), verbose=False) data = logparser.extract_category(data, "jit-log-opt-") storage = LoopStorage() traces = [SimpleParser.parse_from_input(t) for t in data] traces = storage.reconnect_loops(traces) return [Trace(t) for t in traces]
def run(self, topaz, tmpdir, code): tmpdir.join("t.rb").write(code) proc = subprocess.Popen( [str(topaz), str(tmpdir.join("t.rb"))], cwd=str(tmpdir), env={"PYPYLOG": "jit-log-opt:%s" % tmpdir.join("x.pypylog")} ) proc.wait() data = logparser.parse_log_file(str(tmpdir.join("x.pypylog")), verbose=False) data = logparser.extract_category(data, "jit-log-opt-") storage = LoopStorage() traces = [SimpleParser.parse_from_input(t) for t in data] traces = storage.reconnect_loops(traces) return [Trace(t) for t in traces]
def extract_traces(file, remove_debug=True, remove_main_labels=True, remove_all_labels=False): data = logparser.parse_log_file(file, verbose=False) data = logparser.extract_category(data, "jit-log-opt-") storage = LoopStorage() traces = [SimpleParser.parse_from_input(t) for t in data] main_loops = storage.reconnect_loops(traces) traces_w = [] for trace in traces: if trace in main_loops: traces_w.append(Trace(trace)) else: traces_w[len(traces_w) - 1].addbridge(trace) for trace in traces_w: trace.parse(remove_debug, remove_main_labels, remove_all_labels) return traces_w
def main(argv): log = logparser.parse_log_file(argv[0]) parts = logparser.extract_category(log, "jit-log-opt-") for i, oplist in enumerate(parts): loop = parse(oplist, no_namespace=True, nonstrict=True) num_ops = 0 num_dmp = 0 num_guards = 0 for op in loop.operations: if op.getopnum() == rop.DEBUG_MERGE_POINT: num_dmp += 1 else: num_ops += 1 if op.is_guard(): num_guards += 1 if num_dmp == 0: print "Loop #%d, length: %d, opcodes: %d, guards: %d" % (i, num_ops, num_dmp, num_guards) else: print "Loop #%d, length: %d, opcodes: %d, guards: %d, %f" % (i, num_ops, num_dmp, num_guards, num_ops/num_dmp)
def run(self, spy, tmpdir, code): proc = subprocess.Popen( [str(spy), "-r", code.replace("\n", "\r\n"), BenchmarkImage], cwd=str(tmpdir), env={"PYPYLOG": "jit-log-opt:%s" % tmpdir.join("x.pypylog")} ) proc.wait() data = logparser.parse_log_file(str(tmpdir.join("x.pypylog")), verbose=False) data = logparser.extract_category(data, "jit-log-opt-") storage = LoopStorage() traces = [SimpleParser.parse_from_input(t) for t in data] main_loops = storage.reconnect_loops(traces) traces_w = [] for trace in traces: if trace in main_loops: traces_w.append(Trace(trace)) else: traces_w[len(traces_w) - 1].addbridge(trace) return traces_w
def main(argv): log = logparser.parse_log_file(argv[0]) parts = logparser.extract_category(log, "jit-log-opt-") for i, oplist in enumerate(parts): loop = parse(oplist, no_namespace=True, nonstrict=True) num_ops = 0 num_dmp = 0 num_guards = 0 for op in loop.operations: if op.getopnum() == rop.DEBUG_MERGE_POINT: num_dmp += 1 else: num_ops += 1 if op.is_guard(): num_guards += 1 if num_dmp == 0: print "Loop #%d, length: %d, opcodes: %d, guards: %d" % ( i, num_ops, num_dmp, num_guards) else: print "Loop #%d, length: %d, opcodes: %d, guards: %d, %f" % ( i, num_ops, num_dmp, num_guards, num_ops / num_dmp)
def main(loopfile, use_threshold, view=True): countname = py.path.local(loopfile + '.count') if countname.check(): #counts = [line.split(':', 1) for line in countname.readlines()] #counts = Counts([('<code' + k.strip("\n"), int(v.strip('\n').strip())) # for v, k in counts]) counts = Counts([]) l = list(sorted(counts.values())) if len(l) > 20 and use_threshold: counts.threshold = l[-20] else: counts.threshold = 0 for_print = [(v, k) for k, v in counts.iteritems()] for_print.sort() else: counts = {} log = logparser.parse_log_file(loopfile) loops = logparser.extract_category(log, "jit-log-opt-") real_loops, allloops = splitloops(loops) postprocess(real_loops, allloops, counts) if view: Page(allloops, counts).display()
def test(self): def fn_with_bridges(N): def is_prime(x): for y in xrange(2, x): if x % y == 0: return False return True result = 0 for x in xrange(N): if x % 3 == 0: result += 5 elif x % 5 == 0: result += 3 elif is_prime(x): result += x elif x == 99: result *= 2 return result # N = 10000 _log = self.run(fn_with_bridges, [N]) log, loops = import_log(_log.logfile) parse_log_counts(extract_category(log, 'jit-backend-count'), loops) is_prime_loops = [] fn_with_bridges_loops = [] bridges = {} lib_re = re.compile("file '.*lib-python.*'") for loop in loops: if hasattr(loop, 'force_asm'): try: loop.force_asm() except ObjdumpNotFound: py.test.skip("ObjDump was not found, skipping") if lib_re.search(loop.comment) or \ lib_re.search(loop.operations[0].repr()): # do not care for _optimize_charset or _mk_bitmap continue assert loop.count > 0 if ' is_prime, ' in loop.comment: is_prime_loops.append(loop) elif ' fn_with_bridges, ' in loop.comment: fn_with_bridges_loops.append(loop) else: assert ' bridge ' in loop.comment key = mangle_descr(loop.descr) assert key not in bridges bridges[key] = loop by_count = lambda l: -l.count is_prime_loops.sort(key=by_count) fn_with_bridges_loops.sort(key=by_count) # check that we can find bridges corresponding to " % 3" and " % 5" mod_bridges = [] for op in fn_with_bridges_loops[0].operations: if op.descr is not None: bridge = bridges.get(mangle_descr(op.descr)) if bridge is not None: mod_bridges.append(bridge) assert len(mod_bridges) in (1, 2) # check that counts are reasonable (precise # may change in the future) assert N - 2000 < sum(l.count for l in fn_with_bridges_loops) < N
sys.modules['rpython.tool.udir'] = mod rpython.tool.udir = mod if '--text' in sys.argv: sys.argv.remove('--text') showgraph = False else: showgraph = True if len(sys.argv) != 2: print >> sys.stderr, __doc__ sys.exit(2) # import cStringIO from rpython.tool import logparser log1 = logparser.parse_log_file(sys.argv[1]) text1 = logparser.extract_category(log1, catprefix='jit-backend-dump') f = cStringIO.StringIO() f.writelines(text1) f.seek(0) del log1, text1 # world = World() world.parse(f) if showgraph: world.find_cross_references() world.show(showtext=True) else: world.showtextonly() else: from rpython.tool.udir import udir tmpfile = str(udir.join('dump.tmp'))
import sys, re from rpython.tool import logparser # fflush(pypy_debug_file) if len(sys.argv) != 3: print "Usage: %s <log file> <address>" % sys.argv[0] log = logparser.parse_log_file(sys.argv[1]) text = logparser.extract_category(log, catprefix='jit-backend') address = int(sys.argv[2], 16) for l in text: m = re.match('(Loop|Bridge)(.*?) \(.*has address (\w+) to (\w+)', l) if m is not None: trace = m.group(1) + m.group(2) start = int(m.group(3), 16) stop = int(m.group(4), 16) if start <= address <= stop: offset = address - start print trace print 'at offset ', offset break else: print "Not found" exit(0) if trace.startswith('Bridge'): cat = 'jit-log-opt-bridge' else: cat = 'jit-log-opt-loop'
import re from rpython.tool import logparser log = logparser.parse_log_file("log") log = logparser.extract_category(log, "jit-log-opt") d = {} counted = 0 not_counted = 0 result = {} for item in log: first = item.split("\n")[0] if '# Loop' in first: m = re.search("<code object (.*), file '(.*)', line (\d+)", first) if not m: continue key = (m.group(1), m.group(2), int(m.group(3))) for i, op in enumerate(item.split("\n")[2:-1]): if 'guard_' in op: m = re.search("descr=<Guard(0x[0-9a-f]+)>", op) d[int(m.group(1), 16)] = (key, i) #print op, i, int(m.group(1), 16) else: m = re.search("bridge out of Guard (0x[a-f0-9]+)", first) bridge_no = int(m.group(1), 16) if bridge_no in d: result.setdefault(d[bridge_no][0], []).append((bridge_no, d[bridge_no][1])) else: not_counted += 1 for i, op in enumerate(item.split("\n")[2:-1]): if 'guard_' in op:
def run(self, func_or_src, args=[], import_site=False, discard_stdout_before_last_line=False, **jitopts): jitopts.setdefault('threshold', 200) src = py.code.Source(func_or_src) if isinstance(func_or_src, types.FunctionType): funcname = func_or_src.func_name else: funcname = 'main' # write the snippet arglist = ', '.join(map(repr, args)) with self.filepath.open("w") as f: # we don't want to see the small bridges created # by the checkinterval reaching the limit f.write("import sys\n") f.write("sys.setcheckinterval(10000000)\n") f.write(str(src) + "\n") f.write("print %s(%s)\n" % (funcname, arglist)) # # run a child pypy-c with logging enabled logfile = self.filepath.new(ext='.log') # cmdline = [sys.executable] if not import_site: cmdline.append('-S') if jitopts: jitcmdline = [ '%s=%s' % (key, value) for key, value in jitopts.items() ] cmdline += ['--jit', ','.join(jitcmdline)] cmdline.append(str(self.filepath)) # env = os.environ.copy() env['PYPYLOG'] = self.log_string + ':' + str(logfile) pipe = subprocess.Popen(cmdline, env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = pipe.communicate() if pipe.wait() < 0: raise IOError("subprocess was killed by signal %d" % (pipe.returncode, )) if stderr.startswith('SKIP:'): py.test.skip(stderr) if stderr.startswith('debug_alloc.h:'): # lldebug builds stderr = '' assert not stderr # if discard_stdout_before_last_line: stdout = stdout.splitlines(True)[-1] # # parse the JIT log rawlog = logparser.parse_log_file(str(logfile)) rawtraces = logparser.extract_category(rawlog, 'jit-log-opt-') log = Log(rawtraces) log.result = eval(stdout) log.logfile = str(logfile) # summaries = logparser.extract_category(rawlog, 'jit-summary') if len(summaries) > 0: log.jit_summary = parse_prof(summaries[-1]) else: log.jit_summary = None # return log
return _Page(self.graph_builder) # ____________________________________________________________ if __name__ == '__main__': if '--text' in sys.argv: sys.argv.remove('--text') showgraph = False else: showgraph = True if len(sys.argv) != 2: print >> sys.stderr, __doc__ sys.exit(2) # import cStringIO from rpython.tool import logparser log1 = logparser.parse_log_file(sys.argv[1]) text1 = logparser.extract_category(log1, catprefix='jit-backend-dump') f = cStringIO.StringIO() f.writelines(text1) f.seek(0) del log1, text1 # world = World() world.parse(f) if showgraph: world.find_cross_references() world.show(showtext=True) else: world.showtextonly()
def test(self): def fn_with_bridges(N): def is_prime(x): for y in xrange(2, x): if x % y == 0: return False return True result = 0 for x in xrange(N): if x % 3 == 0: result += 5 elif x % 5 == 0: result += 3 elif is_prime(x): result += x elif x == 99: result *= 2 return result # N = 10000 _log = self.run(fn_with_bridges, [N]) log, loops = import_log(_log.logfile) parse_log_counts(extract_category(log, 'jit-backend-count'), loops) is_prime_loops = [] fn_with_bridges_loops = [] bridges = {} lib_re = re.compile("file '.*lib-python.*'") for loop in loops: if hasattr(loop, 'force_asm'): try: loop.force_asm() except ObjdumpNotFound: py.test.skip("ObjDump was not found, skipping") if lib_re.search(loop.comment) or \ lib_re.search(loop.operations[0].repr()): # do not care for _optimize_charset or _mk_bitmap continue assert loop.count > 0 if ' is_prime, ' in loop.comment: is_prime_loops.append(loop) elif ' fn_with_bridges, ' in loop.comment: fn_with_bridges_loops.append(loop) else: assert ' bridge ' in loop.comment key = mangle_descr(loop.descr) assert key not in bridges bridges[key] = loop by_count = lambda l: -l.count is_prime_loops.sort(key=by_count) fn_with_bridges_loops.sort(key=by_count) # check that we can find bridges corresponding to " % 3" and " % 5" mod_bridges = [] for op in fn_with_bridges_loops[0].operations: if op.descr is not None: bridge = bridges.get(mangle_descr(op.descr)) if bridge is not None: mod_bridges.append(bridge) assert len(mod_bridges) in (1, 2, 3) # check that counts are reasonable (precise # may change in the future) assert N - 2000 < sum(l.count for l in fn_with_bridges_loops) < N + 1500