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
|
#!/usr/bin/env python3
# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Plots the distribution of allocated and unallocated slots in SlotSpans.
To run this:
1. Build pa_tcache_inspect at a "close-enough" revision to the Chrome instance
you're interested in.
2. Run pa_tcache_inspect --pid=PID_OF_RUNNING_CHROME_PROCESS --json=output.json
3. Run plot_bucket_stats.py --json=output.json --output=output.png
"""
import argparse
import json
import matplotlib
from matplotlib import pylab as plt
import numpy as np
def ParseJson(filename):
with open(filename, 'r') as f:
data = json.load(f)
return data
def PlotData(data, output_filename):
rows, cols = 6, 5
fig, axs = plt.subplots(rows, cols, figsize=(30, 30))
fig.suptitle('Active Slot Spans fill-in - %s' % output_filename, fontsize=16)
for index, bucket in enumerate(data['buckets'][:rows * cols]):
ax = axs[int(index / cols), index % cols]
active_slot_spans = bucket['active_slot_spans']
freelist_sizes = np.array([
s['freelist_size'] if not s['is_decommitted'] else 0
for s in active_slot_spans
])
allocated_slots = np.array(
[s['num_allocated_slots'] for s in active_slot_spans])
unprovisioned_slots = np.array(
[s['num_unprovisioned_slots'] for s in active_slot_spans])
hatch = ['//' if s['freelist_is_sorted'] else '' for s in active_slot_spans]
slot_size = bucket['slot_size']
allocated_size = bucket['allocated_slots'] * slot_size
free_size = bucket['freelist_size'] * slot_size
ax.set_title('Slot span = %d\nAllocated size = %dkiB, Free size = %dkiB' %
(slot_size, allocated_size // 1024, free_size // 1024))
indices = range(len(active_slot_spans))
bottom = np.zeros(len(indices))
b1 = ax.bar(indices, allocated_slots, bottom=bottom, color='green')
bottom += allocated_slots
b2 = ax.bar(indices,
freelist_sizes,
bottom=bottom,
color=[
'darkgrey' if s['is_decommitted'] else 'red'
for s in active_slot_spans
],
hatch=hatch)
bottom += freelist_sizes
ax.bar(indices, unprovisioned_slots, bottom=bottom, color='lightgrey')
ax.set_xlim(left=-.5, right=len(indices) - .5)
fig.tight_layout()
fig.subplots_adjust(top=.95)
handles = [
matplotlib.patches.Patch(facecolor='green', label='Allocated'),
matplotlib.patches.Patch(facecolor='red',
hatch='//',
label='Sorted freelist'),
matplotlib.patches.Patch(facecolor='red', label='Free'),
matplotlib.patches.Patch(facecolor='grey', label='Unprovisioned'),
matplotlib.patches.Patch(facecolor='darkgrey', label='Decommitted')
]
fig.legend(handles=handles, loc='lower right', fontsize=20)
plt.savefig(output_filename)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--json',
help='JSON dump from pa_tcache_inspect',
required=True)
parser.add_argument('--output_prefix',
help='Output file prefix',
required=True)
args = parser.parse_args()
data = ParseJson(args.json)
PlotData(data, args.output_prefix)
if __name__ == '__main__':
main()
|