コード例 #1
0
ファイル: profiling.py プロジェクト: tltx/iommi
    def __call__(self, request):
        # Disable profiling early on /media requests since touching request.user will add a
        # "Vary: Cookie" header to the response.
        request.profiler_disabled = False
        for prefix in MEDIA_PREFIXES:
            if request.path.startswith(prefix):
                request.profiler_disabled = True
                break

        if should_profile(request):
            self.prof = cProfile.Profile()
            self.prof.enable()

        response = self.get_response(request)

        if should_profile(request):
            response = HttpResponse()
            self.prof.disable()

            import pstats
            s = StringIO()
            ps = pstats.Stats(self.prof, stream=s).sort_stats(
                request.GET.get('_iommi_prof') or 'cumulative')
            ps.print_stats()

            stats_str = s.getvalue()

            if 'graph' in request.GET:
                with NamedTemporaryFile() as stats_dump:
                    ps.stream = stats_dump
                    ps.dump_stats(stats_dump.name)

                    gprof2dot_path = Path(sys.executable).parent / 'gprof2dot'
                    if not gprof2dot_path.exists():
                        raise Exception(
                            'gprof2dot not found. Please install it to use the graph feature.'
                        )

                    gprof2dot = subprocess.Popen(
                        (sys.executable, gprof2dot_path, '-f', 'pstats',
                         stats_dump.name),
                        stdout=subprocess.PIPE)

                    response['Content-Type'] = 'image/svg+xml'

                    dot_path = get_dot_path()
                    if dot_path:
                        response.content = subprocess.check_output(
                            (dot_path, '-Tsvg'), stdin=gprof2dot.stdout)
                    else:
                        response['Content-Type'] = 'text/plain'
                        response[
                            'Content-Disposition'] = "attachment; filename=gprof2dot-graph.txt"
                        response.content = subprocess.check_output(
                            'tee', stdin=gprof2dot.stdout)

            else:
                limit = 280
                result = []

                def strip_extra_path(s, token):
                    if token not in s:
                        return s
                    pre, _, post = s.rpartition(' ')
                    post = post[post.rindex(token) + len(token):]
                    return f'{pre} {post}'

                for line in stats_str.split("\n")[:limit]:
                    should_bold = settings.BASE_DIR in line and '/site-packages/' not in line
                    line = line.replace(settings.BASE_DIR, '')
                    line = strip_extra_path(line, '/site-packages')
                    line = strip_extra_path(line, '/Python.framework/Versions')
                    if should_bold:
                        line = f'<b>{line}</b>'

                    line = line.replace(' ', '&nbsp;')
                    result.append(line)

                response.content = '<div style="font-family: monospace; white-space: nowrap">%s</div' % "<br />\n".join(
                    result)

                response['Content-Type'] = 'text/html'

        return response
コード例 #2
0
    def __call__(self, request):
        # Disable profiling early on /media requests since touching request.user will add a
        # "Vary: Cookie" header to the response.
        request.profiler_disabled = False
        for prefix in MEDIA_PREFIXES:
            if request.path.startswith(prefix):
                request.profiler_disabled = True
                break
        if not request.profiler_disabled and (
                settings.DEBUG
                or request.user.is_staff) and 'prof' in request.GET:
            self.prof = cProfile.Profile()
            self.prof.enable()

        response = self.get_response(request)

        disabled = getattr(request, 'profiler_disabled', True)
        is_staff = hasattr(request, 'user') and request.user.is_staff

        if 'prof' in request.GET and not disabled and is_staff:
            response = HttpResponse()
            self.prof.disable()

            import pstats
            s = StringIO()
            ps = pstats.Stats(self.prof, stream=s).sort_stats(
                request.GET.get('prof') or 'cumulative')
            ps.print_stats()

            stats_str = s.getvalue()

            if 'graph' in request.GET:
                with NamedTemporaryFile() as stats_dump:
                    ps.stream = stats_dump
                    ps.dump_stats(stats_dump.name)

                    gprof2dot_path = os.path.join(
                        os.path.dirname(os.path.abspath(__file__)), 'bin',
                        'profiling', 'gprof2dot.py')
                    gprof2dot = subprocess.Popen(
                        ('python', gprof2dot_path, '-f', 'pstats',
                         stats_dump.name),
                        stdout=subprocess.PIPE)

                    response['Content-Type'] = 'image/svg+xml'
                    if os.path.exists('/usr/bin/dot'):
                        response.content = subprocess.check_output(
                            ('/usr/bin/dot', '-Tsvg'), stdin=gprof2dot.stdout)
                    elif os.path.exists('/usr/local/bin/dot'):
                        response.content = subprocess.check_output(
                            ('/usr/local/bin/dot', '-Tsvg'),
                            stdin=gprof2dot.stdout)
                    else:
                        response['Content-Type'] = 'text/plain'
                        response[
                            'Content-Disposition'] = "attachment; filename=gprof2dot-graph.txt"
                        response.content = subprocess.check_output(
                            'tee', stdin=gprof2dot.stdout)

            else:
                limit = 280
                result = []

                def strip_extra_path(s, token):
                    if token not in s:
                        return s
                    pre, _, post = s.rpartition(' ')
                    post = post[post.rindex(token) + len(token):]
                    return f'{pre} {post}'

                for line in stats_str.split("\n")[:limit]:
                    should_bold = settings.BASE_DIR in line and '/site-packages/' not in line or '/tri/' in line
                    line = line.replace(settings.BASE_DIR, '')
                    line = strip_extra_path(line, '/site-packages')
                    line = strip_extra_path(line, '/Python.framework/Versions')
                    if should_bold:
                        line = f'<b>{line}</b>'

                    line = line.replace(' ', '&nbsp;')
                    result.append(line)

                response.content = '<div style="font-family: monospace; white-space: nowrap">%s</div' % "<br />\n".join(
                    result)

                response['Content-Type'] = 'text/html'

        return response