File: timer.py

package info (click to toggle)
python-django-debug-toolbar 1%3A6.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,084 kB
  • sloc: python: 7,661; javascript: 636; makefile: 67; sh: 16
file content (126 lines) | stat: -rw-r--r-- 4,680 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
from time import perf_counter

from django.template.loader import render_to_string
from django.templatetags.static import static
from django.utils.translation import gettext_lazy as _

from debug_toolbar.panels import Panel

try:
    import resource  # Not available on Win32 systems
except ImportError:
    resource = None


class TimerPanel(Panel):
    """
    Panel that displays the time a response took in milliseconds.
    """

    is_async = True

    def nav_subtitle(self):
        stats = self.get_stats()
        if stats.get("utime"):
            utime = stats.get("utime")
            stime = stats.get("stime")
            return _("CPU: %(cum)0.2fms (%(total)0.2fms)") % {
                "cum": (utime + stime),
                "total": stats["total_time"],
            }
        elif "total_time" in stats:
            return _("Total: %0.2fms") % stats["total_time"]
        else:
            return ""

    has_content = resource is not None

    title = _("Time")

    template = "debug_toolbar/panels/timer.html"

    @property
    def content(self):
        stats = self.get_stats()
        rows = (
            (_("User CPU time"), _("%(utime)0.3f msec") % stats),
            (_("System CPU time"), _("%(stime)0.3f msec") % stats),
            (_("Total CPU time"), _("%(total)0.3f msec") % stats),
            (_("Elapsed time"), _("%(total_time)0.3f msec") % stats),
            (
                _("Context switches"),
                _("%(vcsw)d voluntary, %(ivcsw)d involuntary") % stats,
            ),
        )
        return render_to_string(self.template, {"rows": rows})

    @property
    def scripts(self):
        scripts = super().scripts
        scripts.append(static("debug_toolbar/js/timer.js"))
        return scripts

    def process_request(self, request):
        self._start_time = perf_counter()
        if self.has_content:
            self._start_rusage = resource.getrusage(resource.RUSAGE_SELF)
        return super().process_request(request)

    def serialize_rusage(self, data):
        fields_to_serialize = [
            "ru_utime",
            "ru_stime",
            "ru_nvcsw",
            "ru_nivcsw",
            "ru_minflt",
            "ru_majflt",
        ]
        return {field: getattr(data, field) for field in fields_to_serialize}

    def generate_stats(self, request, response):
        stats = {}
        if hasattr(self, "_start_time"):
            stats["total_time"] = (perf_counter() - self._start_time) * 1000
        if self.has_content:
            self._end_rusage = resource.getrusage(resource.RUSAGE_SELF)
            start = self.serialize_rusage(self._start_rusage)
            end = self.serialize_rusage(self._end_rusage)
            stats.update(
                {
                    "utime": 1000 * self._elapsed_ru(start, end, "ru_utime"),
                    "stime": 1000 * self._elapsed_ru(start, end, "ru_stime"),
                    "vcsw": self._elapsed_ru(start, end, "ru_nvcsw"),
                    "ivcsw": self._elapsed_ru(start, end, "ru_nivcsw"),
                    "minflt": self._elapsed_ru(start, end, "ru_minflt"),
                    "majflt": self._elapsed_ru(start, end, "ru_majflt"),
                }
            )
            stats["total"] = stats["utime"] + stats["stime"]
            # these are documented as not meaningful under Linux.  If you're
            # running BSD feel free to enable them, and add any others that I
            # hadn't gotten to before I noticed that I was getting nothing but
            # zeroes and that the docs agreed. :-(
            #
            #        stats['blkin'] = self._elapsed_ru(start, end, 'ru_inblock')
            #        stats['blkout'] = self._elapsed_ru(start, end, 'ru_oublock')
            #        stats['swap'] = self._elapsed_ru(start, end, 'ru_nswap')
            #        stats['rss'] = self._end_rusage.ru_maxrss
            #        stats['srss'] = self._end_rusage.ru_ixrss
            #        stats['urss'] = self._end_rusage.ru_idrss
            #        stats['usrss'] = self._end_rusage.ru_isrss

        self.record_stats(stats)

    def generate_server_timing(self, request, response):
        stats = self.get_stats()

        self.record_server_timing("utime", "User CPU time", stats.get("utime", 0))
        self.record_server_timing("stime", "System CPU time", stats.get("stime", 0))
        self.record_server_timing("total", "Total CPU time", stats.get("total", 0))
        self.record_server_timing(
            "total_time", "Elapsed time", stats.get("total_time", 0)
        )

    @staticmethod
    def _elapsed_ru(start, end, name):
        return end.get(name) - start.get(name)