diff options
Diffstat (limited to 'debug_toolbar')
| -rw-r--r-- | debug_toolbar/panels/cache.py | 102 | ||||
| -rw-r--r-- | debug_toolbar/templates/debug_toolbar/panels/cache.html | 54 |
2 files changed, 156 insertions, 0 deletions
diff --git a/debug_toolbar/panels/cache.py b/debug_toolbar/panels/cache.py new file mode 100644 index 0000000..fa6bdd0 --- /dev/null +++ b/debug_toolbar/panels/cache.py @@ -0,0 +1,102 @@ +import time +import inspect +try: + from cStringIO import StringIO +except ImportError: + import StringIO +from django.core import cache +from django.core.cache.backends.base import BaseCache +from django.template.loader import render_to_string +from debug_toolbar.panels import DebugPanel + +class CacheStatTracker(BaseCache): + """A small class used to track cache calls.""" + def __init__(self, cache): + self.cache = cache + self.reset() + + def reset(self): + self.calls = [] + self.hits = 0 + self.misses = 0 + self.sets = 0 + self.gets = 0 + self.get_many = 0 + self.deletes = 0 + self.total_time = 0 + + def _get_func_info(self): + stack = inspect.stack()[2] + return (stack[1], stack[2], stack[3], stack[4]) + + def get(self, key, default=None): + t = time.time() + value = self.cache.get(key, default) + this_time = time.time() - t + self.total_time += this_time * 1000 + if value is None: + self.misses += 1 + else: + self.hits += 1 + self.gets += 1 + self.calls.append((this_time, 'get', (key,), self._get_func_info())) + return value + + def set(self, key, value, timeout=None): + t = time.time() + self.cache.set(key, value, timeout) + this_time = time.time() - t + self.total_time += this_time * 1000 + self.sets += 1 + self.calls.append((this_time, 'set', (key, value, timeout), self._get_func_info())) + + def delete(self, key): + t = time.time() + self.instance.delete(key, value) + this_time = time.time() - t + self.total_time += this_time * 1000 + self.deletes += 1 + self.calls.append((this_time, 'delete', (key,), self._get_func_info())) + + def get_many(self, keys): + t = time.time() + results = self.cache.get_many(keys) + this_time = time.time() - t + self.total_time += this_time * 1000 + self.get_many += 1 + for key, value in results.iteritems(): + if value is None: + self.misses += 1 + else: + self.hits += 1 + self.calls.append((this_time, 'get_many', (keys,), self._get_func_info())) + +class CacheDebugPanel(DebugPanel): + """ + Panel that displays the cache statistics. + """ + name = 'Cache' + + def __init__(self, request): + # This is hackish but to prevent threading issues is somewhat needed + if isinstance(cache.cache, CacheStatTracker): + cache.cache.reset() + self.cache = cache.cache + else: + self.cache = CacheStatTracker(cache.cache) + cache.cache = self.cache + super(CacheDebugPanel, self).__init__(request) + + def title(self): + return 'Cache: %.2fms' % self.cache.total_time + + def url(self): + return '' + + def content(self): + context = dict( + cache_calls = len(self.cache.calls), + cache_time = self.cache.total_time, + cache = self.cache, + ) + return render_to_string('debug_toolbar/panels/cache.html', context)
\ No newline at end of file diff --git a/debug_toolbar/templates/debug_toolbar/panels/cache.html b/debug_toolbar/templates/debug_toolbar/panels/cache.html new file mode 100644 index 0000000..9d51404 --- /dev/null +++ b/debug_toolbar/templates/debug_toolbar/panels/cache.html @@ -0,0 +1,54 @@ +<h3>Cache Usage</h3> +<table> + <colgroup> + <col width="12%"/> + <col width="12%"/> + <col width="12%"/> + <col width="12%"/> + <col width="12%"/> + <col width="12%"/> + <col width="12%"/> + <col width="12%"/> + </colgroup> + <tr> + <th>Total Calls</th> + <td>{{ cache_calls }}</td> + <th>Total Time</th> + <td>{{ cache_time }}</td> + <th>Hits</th> + <td>{{ cache.hits }}</td> + <th>Misses</th> + <td>{{ cache.misses }}</td> + </tr> + <tr> + <th>gets</th> + <td>{{ cache.gets }}</td> + <th>sets</th> + <td>{{ cache.sets }}</td> + <th>deletes</th> + <td>{{ cache.deletes }}</td> + <th>get_many</th> + <td>{{ cache.get_many }}</td> + </tr> +</table> +<h3>Breakdown</h3> +<table> + <thead> + <tr> + <th>Time (ms)</th> + <th>Type</th> + <th>Parameters</th> + <th>Function</th> + </tr> + </thead> + <tbody> + {% for query in cache.calls %} + <tr class="{% cycle 'row1' 'row2' %}"> + <td>{{ query.0|floatformat:"4" }}</td> + <td>{{ query.1|escape }}</td> + <td>{{ query.2|escape }}</td> + <td><acronym title="{{ query.3.0 }}:{{ query.3.1 }}">{{ query.3.2|escape }}</acronym>: {{ query.3.3.0|escape }}</td> + </tr> + {% endfor %} + </tbody> +</table>
\ No newline at end of file |
