Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Add a memory overview line when memory sampling is on.

Summary:
Shows the initial, final, and maximum memory.  This should make it easier to
see when there may be something worth looking at in the memory profile.

Test Plan: Load the homepage.

Reviewers: alan

Reviewed By: alan

Differential Revision: http://phabricator.khanacademy.org/D10625
  • Loading branch information...
commit 77d0e3b1611ae34d779025c7ce06100eeee0a983 1 parent 8db7eb1
@benjaminjkraft benjaminjkraft authored
Showing with 20 additions and 5 deletions.
  1. +13 −5 sampling_profiler.py
  2. +7 −0 static/js/template.tmpl
View
18 sampling_profiler.py
@@ -18,7 +18,7 @@
the question, "Where is the time spent by my app?"
"""
-from collections import defaultdict
+import collections
import logging
import sys
import time
@@ -98,6 +98,9 @@ def run(self):
if seconds_to_sleep > 0:
time.sleep(seconds_to_sleep)
+ # Always take a sample at the end.
+ self.profile.take_sample(sample_number, force_memory=True)
+
class ProfileSample(object):
"""Single stack trace sample gathered during a periodic inspection."""
@@ -153,7 +156,7 @@ def __init__(self, memory_sample_rate=0):
self.samples = []
# All saved memory samples in MB, by timestamp_ms
- self.memory_samples = {}
+ self.memory_samples = collections.OrderedDict()
# Thread id for the request thread currently being profiled
self.current_request_thread_id = None
@@ -165,7 +168,7 @@ def __init__(self, memory_sample_rate=0):
def results(self):
"""Return sampling results in a dictionary for template context."""
- aggregated_calls = defaultdict(int)
+ aggregated_calls = collections.defaultdict(int)
total_samples = len(self.samples)
# Compress the results by keeping an array of all of the frame
@@ -200,6 +203,11 @@ def results(self):
util.short_method_fmt(frame) for frame in frames],
"samples": samples,
"total_samples": total_samples,
+ # We always take a memory sample at the end, so the following
+ # are safe.
+ "start_memory": round(self.memory_samples.values()[0], 2),
+ "max_memory": round(max(self.memory_samples.values()), 2),
+ "end_memory": round(self.memory_samples.values()[-1], 2),
}
@staticmethod
@@ -222,7 +230,7 @@ def annotate_prev_samples(samples, key, rev=False):
if sample['memory_used'] is not None:
prev_index = i
- def take_sample(self, sample_number):
+ def take_sample(self, sample_number, force_memory=False):
timestamp_ms = (time.time() - self.start_time) * 1000
# Look at stacks of all existing threads...
# See http://bzimmer.ziclix.com/2008/12/17/python-thread-dumps/
@@ -236,7 +244,7 @@ def take_sample(self, sample_number):
self.samples.append(ProfileSample.from_frame_and_timestamp(
active_frame, timestamp_ms))
if self.memory_sample_every:
- if sample_number % self.memory_sample_every == 0:
+ if force_memory or sample_number % self.memory_sample_every == 0:
self.memory_samples[timestamp_ms] = get_memory()
def run(self, fxn):
View
7 static/js/template.tmpl
@@ -36,6 +36,13 @@
<div class="title">
<div class="header">
${profiler_results.total_time} <span class="ms">ms</span>: <span class="url" title="${url}">${url}</span>
+ {{if GaeMiniProfiler.isMemorySamplingEnabled(mode)}}
+ <br/>
+ Memory:
+ ${profiler_results.start_memory} MB (start),
+ ${profiler_results.max_memory} MB (max),
+ ${profiler_results.end_memory} MB (end)
+ {{/if}}
</div>
</div>
Please sign in to comment.
Something went wrong with that request. Please try again.