class ProfilerMiddleware(object): def __init__(self): self.profiler = None def process_request(self, request): if getattr(settings, 'PYINSTRUMENT_URL_ARGUMENT', 'profile') in request.GET: self.profiler = Profiler() try: self.profiler.start() except NotMainThreadError: raise NotMainThreadError(not_main_thread_message) self.profiler = None def process_response(self, request, response): if self.profiler: try: self.profiler.stop() return HttpResponse(self.profiler.output_html()) except NotMainThreadError: raise NotMainThreadError(not_main_thread_message) finally: self.profiler = None else: return response
def main(req: func.HttpRequest) -> func.HttpResponse: logging.info('Python HTTP trigger function processed a request.') # creating random file for each usage of this function f= open("/home/"+str(random.randint(1,1100))+".html","w+") profiler = Profiler(use_signal=False) profiler.start() n = int(req.params.get('n', 15)) if not n: try: req_body = req.get_json() except ValueError: pass else: name = req_body.get('n') if n: output = str(fibnonci_approach(n)) # stopping profiler and writing it to random file generated earlier profiler.stop() f.write(profiler.output_html()) return func.HttpResponse("Fibnonci of " + str(n) + " using regular approach:" + output) else: return func.HttpResponse( "Please pass a name on the query string or in the request body", status_code=400 )
class ManagerProfilePyinstrument(ManagerProfile): def __init__(self, sync: bool): self.sync = sync self.profiler = Profiler() def start(self): self.profiler.start() return nullcontext() def stop_and_write(self, path_profile: str, is_docker: bool, api: str, render_browser: bool = False): self.profiler.stop() mode = "sync" if self.sync else "async" filename = f"pyinstrument_profile_{mode}_{api}.html" if not is_docker: output_html = self.profiler.output_html() self._write_output_file(path_profile, output_html, filename=filename) if render_browser: self.profiler.open_in_browser() print(self.profiler.output_text(unicode=True, color=True)) def _write_output_file(self, path_profile: str, output_html: str, filename: str): output_html_path = self._prepare_output_path(path_profile, filename) with open(output_html_path, "w") as file: file.write(output_html)
class WPInvProfiler(object): def __init__(self, wphase_output, working_dir): self.wphase_output = wphase_output self.working_dir = working_dir def __enter__(self): self.profiler = Profiler( ) # or Profiler(use_signal=False), see below self.profiler.start() def __exit__(self, exc_type, esc_value, traceback): self.profiler.stop() self.wphase_output[settings.WPINV_PROFILE_OUTPUT_KEY] = \ self.profiler.output_html() if self.working_dir is not None: with open(os.path.join(self.working_dir, 'timings.html'), 'w') as timings_file: timings_file.write(self.profiler.output_html())
def _output_html(self, request: HttpRequest, profiler: Profiler): html = profiler.output_html() t = int(time.time() * 1000) key = '{}-{}-{}'.format(t, request.method, request.path) _PROFILER_RECORDS[key] = html while len(_PROFILER_RECORDS) > 20: _PROFILER_RECORDS.popitem(False) port = request.META['SERVER_PORT'] link = f'http://localhost:{port}/__profiler__/{key}' return link
def main(): usage = "usage: %prog [-h] [-o output_file_path] scriptfile [arg] ..." parser = OptionParser(usage=usage) parser.allow_interspersed_args = False parser.add_option('', '--html', dest="output_html", action='store_true', help="output HTML instead of text", default=False) parser.add_option('-o', '--outfile', dest="outfile", action='store', help="save stats to <outfile>", default=None) if not sys.argv[1:]: parser.print_usage() sys.exit(2) (options, args) = parser.parse_args() sys.argv[:] = args if len(args) > 0: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) with open(progname, 'rb') as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, '__name__': '__main__', '__package__': None, } profiler = Profiler() profiler.start() try: exec code in globs, None except SystemExit, KeyboardInterrupt: pass profiler.stop() if options.outfile: f = codecs.open(options.outfile, 'w', 'utf-8') unicode = True color = False else: f = sys.stdout unicode = stdout_supports_unicode() color = stdout_supports_color() if options.output_html: f.write(profiler.output_html()) else: f.write(profiler.output_text(unicode=unicode, color=color)) f.close()
def instrument(filename="results"): profiler = Profiler() directory = Path("profiling/results/") try: profiler.start() yield finally: profiler.stop() directory.mkdir(parents=True, exist_ok=True) path = os.path.join(directory, f"{filename}.html") with open(path, "w") as fs: fs.write(profiler.output_html(timeline=True))
def __call__(self, request: Request) -> Response: if request.args.get("_instrument") != "1": return Response.from_app(self.app, request.environ) profiler = Profiler(interval=self.interval) # call original request fake_start_response = mock.MagicMock() with profiler: self.app(request.environ, fake_start_response) # return HTML profiling information return Response(profiler.output_html(), mimetype="text/html")
class WPInvProfiler(object): """WPInvProfiler.""" def __init__(self, working_dir=None): """__init__. Parameters ---------- working_dir : working_dir """ self.html = None self.working_dir = working_dir def __enter__(self): """__enter__.""" self.profiler = Profiler() # or Profiler(use_signal=False), see below self.profiler.start() def __exit__(self, exc_type, esc_value, traceback): """__exit__. Parameters ---------- exc_type : exc_type esc_value : esc_value traceback : traceback """ self.profiler.stop() self.html = self.profiler.output_html() if self.working_dir is not None: with open( os.path.join(self.working_dir, "timings.html"), "w" ) as timings_file: timings_file.write(self.profiler.output_html())
def _wrapper(*args, **kwargs): _profiler = Profiler( sampling_interval_seconds ) if sampling_interval_seconds is not None else Profiler() _profiler.start() result = _func(*args, **kwargs) _profiler.stop() if print_to_console: print(_profiler.output_text(unicode=True, color=True)) if log_to_file: name = file_name if file_name is not None else _func.__name__ + ".profile" with open(f"{name}.html", "w") as f: f.write(_profiler.output_html()) return result
def run_profiling(args): lprofiler = LineProfiler() monitor_fuctions = [ api.problem.submit_key, api.problem.get_unlocked_pids, api.problem.get_solved_pids, api.problem.get_all_problems, api.problem.get_solved_problems, api.stats.get_score, api.cache.memoize, api.autogen.grade_problem_instance, api.autogen.get_problem_instance, api.autogen.get_number_of_instances ] for func in monitor_fuctions: lprofiler.add_function(func) lprofiler.enable() if args.stack: profiler = Profiler(use_signal=False) profiler.start() for func, a, kw in operations: func(*a, **kw) if args.stack: profiler.stop() lprofiler.disable() if args.print: print(profiler.output_text(unicode=True, color=True)) lprofiler.print_stats() output = open(args.output, "w") if args.stack: output.write(profiler.output_text(unicode=True)) if args.output_html is not None: output_html = open(args.output_html, "w") output_html.write(profiler.output_html()) output_html.close() print("Wrote test info to " + args.output_html) lprofiler.print_stats(output) output.close() print("Wrote test info to " + args.output)
class PyinstrumentPythonProfiler(PythonProfiler): """Higher level class to oversee profiling specific to Pyinstrument, a third party Python profiler. """ _name = PYINSTRUMENT_NAME def _enable_profiler(self): """Enable the pyinstrument profiler. """ self._profiler = PyinstrumentProfiler() self._profiler.start() def _disable_profiler(self): """Disable the pyinstrument profiler. """ self._profiler.stop() def _dump_stats(self, stats_dir): """Dump the stats as a JSON dictionary to a file `python_stats.json` in the provided stats directory. """ stats_file_path = os.path.join(stats_dir, PYINSTRUMENT_JSON_FILENAME) html_file_path = os.path.join(stats_dir, PYINSTRUMENT_HTML_FILENAME) try: session = self._profiler.last_session json_stats = JSONRenderer().render(session) get_logger().info( f"JSON stats collected for pyinstrument: {json_stats}.") with open(stats_file_path, "w") as json_data: json_data.write(json_stats) get_logger().info( f"Dumping pyinstrument stats to {stats_file_path}.") with open(html_file_path, "w") as html_data: html_data.write(self._profiler.output_html()) get_logger().info( f"Dumping pyinstrument output html to {html_file_path}.") except (UnboundLocalError, AssertionError): # Handles error that sporadically occurs within pyinstrument. get_logger().info( f"The pyinstrument profiling session has been corrupted for: {stats_file_path}." ) with open(stats_file_path, "w") as json_data: json.dump({"root_frame": None}, json_data) with open(html_file_path, "w") as html_data: html_data.write("An error occurred during profiling!")
def run_profiling(args): lprofiler = LineProfiler() monitor_fuctions = [api.problem.submit_key, api.problem.get_unlocked_pids, api.problem.get_solved_pids, api.problem.get_all_problems, api.problem.get_solved_problems, api.stats.get_score, api.cache.memoize, api.autogen.grade_problem_instance, api.autogen.get_problem_instance, api.autogen.get_number_of_instances] for func in monitor_fuctions: lprofiler.add_function(func) lprofiler.enable() if args.stack: profiler = Profiler(use_signal=False) profiler.start() for func, a, kw in operations: func(*a, **kw) if args.stack: profiler.stop() lprofiler.disable() if args.print: print(profiler.output_text(unicode=True, color=True)) lprofiler.print_stats() output = open(args.output, "w") if args.stack: output.write(profiler.output_text(unicode=True)) if args.output_html is not None: output_html = open(args.output_html, "w") output_html.write(profiler.output_html()) output_html.close() print("Wrote test info to " + args.output_html) lprofiler.print_stats(output) output.close() print("Wrote test info to " + args.output)
def profiler_endpoint(): # creating a new profiler profiler = Profiler() profiler.start() # code execution - call the recursive function recursive_function(0) # stopping the profiler profiler.stop() # if the execution time pass the goal time a new message is created in pubsub if profiler.last_session.duration > TIME_GOAL: # email_type can be one of the following values: # 1 - text with html report # 2 - text only email_type = '1' # set the email text email_text = f'Hi,\n\n\nThe service has taken more time thant the goal of {TIME_GOAL} seconds.\nMore details in the attached html report.\n\n\nThanks.' # set the email subject email_subject = 'Execution time of the service' # set the email that will be identified as the emissor from_addrs = '*****@*****.**' # set the list of emails that will receive the report to = ['*****@*****.**', '*****@*****.**'] # set the filename of the report filename = 'filename' # preparing the parameters data = str(profiler.output_html()).encode('utf-8') attributes = { 'type': email_type, 'text': email_text, 'subject': email_subject, 'from_addrs': from_addrs, 'to': ', '.join(to), 'attachment_name': f'{filename}.html' } # publishing a new message in the pubsub topic future = publisher.publish(TOPIC_PATH, data=data, **attributes) return '200'
def launch_experiment(args): set_config('ARGS', args) if args.profile: from pyinstrument import Profiler profiler = Profiler() profiler.start() try: _main(args) except Exception as e: if args.pdb: type, value, tb = sys.exc_info() traceback.print_exc() pdb.post_mortem(tb) else: log.exception(e) critical(None, 'Error starting experiment', str(e)) if args.profile: profiler.stop() html = profiler.output_html() with open('profile.html', 'w') as fh: fh.write(html)
def profile_filterset(self, prof_fs, html_name_suffix_no_ext): print('>>> profile_filterset') profiler = Profiler() profiler.start() # code profile result_qs = prof_fs.qs profiler.stop() #print('>>>', result_qs.values_list('number', flat=True)) len(result_qs) # Make sure no errors when evaluating the qs # Reset the Queryset to run the filters again delattr(prof_fs, '_qs') # Write to HTML with open( F'{self.html_base_name_no_ext}_{html_name_suffix_no_ext}_{self.db_entry_count}.html', 'w') as fptr: fptr.write(profiler.output_html()) print('<<< profile_filterset')
def main(): usage = ("usage: python -m pyinstrument [options] scriptfile [arg] ...") parser = OptionParser(usage=usage) parser.allow_interspersed_args = False parser.add_option('', '--html', dest="output_html", action='store_true', help="output HTML instead of text", default=False) parser.add_option('-o', '--outfile', dest="outfile", action='store', help="save report to <outfile>", default=None) parser.add_option('', '--unicode', dest='unicode', action='store_true', help='force unicode text output') parser.add_option('', '--no-unicode', dest='unicode', action='store_false', help='force ascii text output') parser.add_option('', '--color', dest='color', action='store_true', help='force ansi color text output') parser.add_option('', '--no-color', dest='color', action='store_false', help='force no color text output') if not sys.argv[1:]: parser.print_help() sys.exit(2) (options, args) = parser.parse_args() sys.argv[:] = args if len(args) > 0: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) with open(progname, 'rb') as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, '__name__': '__main__', '__package__': None, } try: profiler = Profiler() except SignalUnavailableError: profiler = Profiler(use_signal=False) profiler.start() try: exec_(code, globs, None) except (SystemExit, KeyboardInterrupt): pass profiler.stop() if options.outfile: f = codecs.open(options.outfile, 'w', 'utf-8') else: f = sys.stdout unicode_override = options.unicode != None color_override = options.color != None unicode = options.unicode if unicode_override else file_supports_unicode(f) color = options.color if color_override else file_supports_color(f) if options.output_html: f.write(profiler.output_html()) else: f.write(profiler.output_text(unicode=unicode, color=color)) f.close() else: parser.print_usage() return parser
from pyinstrument import Profiler from platform import platform p = Profiler() p.start() def func(): fd = open('/dev/urandom', 'rb') _ = fd.read(1024*1024) func() # this failed on ubuntu 12.04 platform() p.stop() print(p.output_text()) with open('ioerror_out.html', 'w') as f: f.write(p.output_html())
def main(): usage = ("usage: pyinstrument [options] scriptfile [arg] ...") parser = OptionParser(usage=usage) parser.allow_interspersed_args = False parser.add_option('', '--setprofile', dest='setprofile', action='store_true', help='run in setprofile mode, instead of signal mode', default=False) parser.add_option('', '--html', dest="output_html", action='store_true', help="output HTML instead of text", default=False) parser.add_option('-o', '--outfile', dest="outfile", action='store', help="save report to <outfile>", default=None) parser.add_option('', '--unicode', dest='unicode', action='store_true', help='force unicode text output') parser.add_option('', '--no-unicode', dest='unicode', action='store_false', help='force ascii text output') parser.add_option('', '--color', dest='color', action='store_true', help='force ansi color text output') parser.add_option('', '--no-color', dest='color', action='store_false', help='force no color text output') if not sys.argv[1:]: parser.print_help() sys.exit(2) (options, args) = parser.parse_args() sys.argv[:] = args if len(args) > 0: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) with open(progname, 'rb') as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, '__name__': '__main__', '__package__': None, } try: profiler = Profiler(use_signal=not options.setprofile) except SignalUnavailableError: profiler = Profiler(use_signal=False) profiler.start() try: exec_(code, globs, None) except IOError as e: import errno if e.errno == errno.EINTR: print( 'Failed to run program due to interrupted system system call.\n' 'This happens because pyinstrument is sending OS signals to the running\n' 'process to interrupt it. If your program has long-running syscalls this\n' 'can cause a problem.\n' '\n' 'You can avoid this error by running in \'setprofile\' mode. Do this by\n' 'passing \'--setprofile\' when calling pyinstrument at the command-line.\n' '\n' 'For more information, see\n' 'https://github.com/joerick/pyinstrument/issues/16\n' ) raise except (SystemExit, KeyboardInterrupt): pass profiler.stop() if options.outfile: f = codecs.open(options.outfile, 'w', 'utf-8') else: f = sys.stdout unicode_override = options.unicode != None color_override = options.color != None unicode = options.unicode if unicode_override else file_supports_unicode(f) color = options.color if color_override else file_supports_color(f) if options.output_html: f.write(profiler.output_html()) else: f.write(profiler.output_text(unicode=unicode, color=color)) f.close() else: parser.print_usage() return parser
def main(): usage = ("usage: python -m pyinstrument [options] scriptfile [arg] ...") parser = OptionParser(usage=usage) parser.allow_interspersed_args = False parser.add_option('', '--html', dest="output_html", action='store_true', help="output HTML instead of text", default=False) parser.add_option('-o', '--outfile', dest="outfile", action='store', help="save report to <outfile>", default=None) parser.add_option('', '--unicode', dest='unicode', action='store_true', help='force unicode text output') parser.add_option('', '--no-unicode', dest='unicode', action='store_false', help='force ascii text output') parser.add_option('', '--color', dest='color', action='store_true', help='force ansi color text output') parser.add_option('', '--no-color', dest='color', action='store_false', help='force no color text output') if not sys.argv[1:]: parser.print_help() sys.exit(2) (options, args) = parser.parse_args() sys.argv[:] = args if len(args) > 0: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) with open(progname, 'rb') as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, '__name__': '__main__', '__package__': None, } try: profiler = Profiler() except SignalUnavailableError: profiler = Profiler(use_signal=False) profiler.start() try: exec_(code, globs, None) except (SystemExit, KeyboardInterrupt): pass profiler.stop() if options.outfile: f = codecs.open(options.outfile, 'w', 'utf-8') else: f = sys.stdout unicode_override = options.unicode != None color_override = options.color != None unicode = options.unicode if unicode_override else file_supports_unicode( f) color = options.color if color_override else file_supports_color(f) if options.output_html: f.write(profiler.output_html()) else: f.write(profiler.output_text(unicode=unicode, color=color)) f.close() else: parser.print_usage() return parser
def profile(fct, sort='cumulative', rootrem=None, as_df=False, pyinst_format=None, **kwargs): """ Profiles the execution of a function. @param fct function to profile @param sort see `sort_stats <https://docs.python.org/3/library/ profile.html#pstats.Stats.sort_stats>`_ @param rootrem root to remove in filenames @param as_df return the results as a dataframe and not text @param pyinst_format format for :epkg:`pyinstrument`, if not empty, the function uses this module or raises an exception if not installed, the options are *text*, *textu* (text with colors), *json*, *html* @param kwargs additional parameters used to create the profiler @return raw results, statistics text dump (or dataframe is *as_df* is True) .. plot:: import matplotlib.pyplot as plt from pyquickhelper.pycode.profiling import profile from pyquickhelper.texthelper import compare_module_version def fctm(): return compare_module_version('0.20.4', '0.22.dev0') pr, df = profile(lambda: [fctm() for i in range(0, 1000)], as_df=True) ax = df[['namefct', 'cum_tall']].head(n=15).set_index( 'namefct').plot(kind='bar', figsize=(8, 3), rot=30) ax.set_title("example of a graph") for la in ax.get_xticklabels(): la.set_horizontalalignment('right'); plt.show() """ if pyinst_format is None: pr = cProfile.Profile(**kwargs) pr.enable() fct() pr.disable() s = StringIO() ps = pstats.Stats(pr, stream=s).sort_stats(sort) ps.print_stats() res = s.getvalue() try: pack = site.getsitepackages() except AttributeError: # pragma: no cover import numpy pack = os.path.normpath( os.path.abspath( os.path.join(os.path.dirname(numpy.__file__), ".."))) pack = [pack] pack_ = os.path.normpath(os.path.join(pack[-1], '..')) def clean_text(res): res = res.replace(pack[-1], "site-packages") res = res.replace(pack_, "lib") if rootrem is not None: if isinstance(rootrem, str): res = res.replace(rootrem, '') else: for sub in rootrem: if isinstance(sub, str): res = res.replace(sub, '') elif isinstance(sub, tuple) and len(sub) == 2: res = res.replace(sub[0], sub[1]) else: raise TypeError( "rootrem must contains strings or tuple not {0}" .format(rootrem)) return res if as_df: def better_name(row): if len(row['fct']) > 15: return "{}-{}".format(row['file'].split(':')[-1], row['fct']) name = row['file'].replace("\\", "/") return "{}-{}".format(name.split('/')[-1], row['fct']) rows = _process_pstats(ps, clean_text) import pandas df = pandas.DataFrame(rows) df = df[[ 'fct', 'file', 'ncalls1', 'ncalls2', 'tin', 'cum_tin', 'tall', 'cum_tall' ]] df['namefct'] = df.apply(lambda row: better_name(row), axis=1) df = df.groupby(['namefct', 'file'], as_index=False).sum().sort_values( 'cum_tall', ascending=False).reset_index(drop=True) return ps, df else: res = clean_text(res) return ps, res elif as_df: raise ValueError( # pragma: no cover "as_df is not a compatible option with pyinst_format") else: try: from pyinstrument import Profiler except ImportError as e: # pragma: no cover raise ImportError("pyinstrument is not installed.") from e profiler = Profiler(**kwargs) profiler.start() fct() profiler.stop() if pyinst_format == "text": return profiler, profiler.output_text(unicode=False, color=False) elif pyinst_format == "textu": return profiler, profiler.output_text(unicode=True, color=True) elif pyinst_format == "json": from pyinstrument.renderers import JSONRenderer return profiler, profiler.output(JSONRenderer()) elif pyinst_format == "html": return profiler, profiler.output_html() else: raise ValueError("Unknown format '{}'.".format(pyinst_format))
####################################### # numpy is much faster and does not always appear # if pydot is run the same number of times. # The program is spied on a given number of times # per seconds, each time the system records # which function the program is executing. # At the end, the profiler is able to approximatvely tell # how long the program stayed in every function. # If a function does not appear, it means it was never executed # or too fast to be caught. # An HTML report can be generated. if profiler is not None: with open("dot_pyinstrument.html", "w", encoding="utf-8") as f: f.write(profiler.output_html()) ####################################### # See :ref:`l-appendix-example-dot-profile`. # :epkg:`pyinstrument` does not measure native function (C++) # very well. For this module :epkg:`py-spy` is more efficient # but it only works in command line as the package itself # is written in :epkg:`RUST` # (see `Taking ML to production with Rust: a 25x speedup # <https://www.lpalmieri.com/posts/ # 2019-12-01-taking-ml-to-production-with-rust-a-25x-speedup/>`_). if profiler is not None: cmd = ("py-spy record --native --function --rate=10 " "-o dotpyspy.svg -- {0} plot_profile.py --pyspy").format(executable) run_cmd(cmd, wait=True, fLOG=print)
from pyinstrument import Profiler from platform import platform p = Profiler() p.start() def func(): fd = open('/dev/urandom', 'rb') data = fd.read(1024*1024) func() # this failed on ubuntu 12.04 platform() p.stop() print(p.output_text()) with open('ioerror_out.html', 'w') as f: f.write(p.output_html())
def main(): usage = ("usage: pyinstrument [options] scriptfile [arg] ...") parser = OptionParser(usage=usage) parser.allow_interspersed_args = False parser.add_option('', '--setprofile', dest='setprofile', action='store_true', help='run in setprofile mode, instead of signal mode', default=False) parser.add_option('', '--html', dest="output_html", action='store_true', help="output HTML instead of text", default=False) parser.add_option('-o', '--outfile', dest="outfile", action='store', help="save report to <outfile>", default=None) parser.add_option('', '--unicode', dest='unicode', action='store_true', help='force unicode text output') parser.add_option('', '--no-unicode', dest='unicode', action='store_false', help='force ascii text output') parser.add_option('', '--color', dest='color', action='store_true', help='force ansi color text output') parser.add_option('', '--no-color', dest='color', action='store_false', help='force no color text output') if not sys.argv[1:]: parser.print_help() sys.exit(2) (options, args) = parser.parse_args() sys.argv[:] = args if len(args) > 0: progname = args[0] sys.path.insert(0, os.path.dirname(progname)) with open(progname, 'rb') as fp: code = compile(fp.read(), progname, 'exec') globs = { '__file__': progname, '__name__': '__main__', '__package__': None, } try: profiler = Profiler(use_signal=not options.setprofile) except SignalUnavailableError: profiler = Profiler(use_signal=False) profiler.start() try: exec_(code, globs, None) except IOError as e: import errno if e.errno == errno.EINTR: print( 'Failed to run program due to interrupted system system call.\n' 'This happens because pyinstrument is sending OS signals to the running\n' 'process to interrupt it. If your program has long-running syscalls this\n' 'can cause a problem.\n' '\n' 'You can avoid this error by running in \'setprofile\' mode. Do this by\n' 'passing \'--setprofile\' when calling pyinstrument at the command-line.\n' '\n' 'For more information, see\n' 'https://github.com/joerick/pyinstrument/issues/16\n') raise except (SystemExit, KeyboardInterrupt): pass profiler.stop() if options.outfile: f = codecs.open(options.outfile, 'w', 'utf-8') else: f = sys.stdout unicode_override = options.unicode != None color_override = options.color != None unicode = options.unicode if unicode_override else file_supports_unicode( f) color = options.color if color_override else file_supports_color(f) if options.output_html: f.write(profiler.output_html()) else: f.write(profiler.output_text(unicode=unicode, color=color)) f.close() else: parser.print_usage() return parser