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
|
# 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.
"""
This script allows us to create a live graph of internal fragmentation in
Chrome, updated as chrome runs.
Usage:
1. Compile chrome with the RECORD_ALLOC_INFO flag.
2. Compile pa_bucket_inspect tool with the RECORD_ALLOC_INFO flag.
3. Start Chrome.
4. Find the PID of the process you wish to create graphs for.
5. run pa_bucket_inspect <PID>
6. run this script.
"""
from sys import argv
import matplotlib.animation as animation
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
def main(argv: list[str]) -> None:
DUMPNAME: final = "dump.dat"
KIB: final = 1024
MIB: final = KIB * 1024
fig, axes = plt.subplots(2, 1)
(ax_a, ax_b) = axes
axes = ax_a, ax_b, ax_c, ax_d
green_patch = mpatches.Patch(color='g', label='Used')
plum_patch = mpatches.Patch(color='plum', label='Wasted')
def animate(i):
bucket_sizes = []
x = []
ya1 = []
ya2 = []
yb1 = []
yb2 = []
with open(DUMPNAME, 'r') as f:
for line in f.readlines():
index, bucket_size, num_allocs_a, total_requested_size_a, num_allocs_b, total_requested_size_b = [
int(tmp) for tmp in line.strip().split(',')
]
def record_allocs_and_sizes(y1, y2, num_allocs, total_requested_size):
y1.append(bucket_size * num_allocs / MIB)
y2.append((bucket_size * num_allocs - total_requested_size) / MIB)
print(index, bucket_size, num_allocs_a, total_requested_size_a,
num_allocs_b, total_requested_size_b)
x.append((index))
# format buckets sizes with commas, e.g. 50000 -> 50,000
bucket_sizes.append('{:,}'.format(bucket_size))
record_allocs_and_sizes(ya1, ya2, num_allocs_a, total_requested_size_a)
record_allocs_and_sizes(yb1, yb2, num_allocs_b, total_requested_size_b)
total_size_a = sum(ya1)
total_size_b = sum(yb1)
def plot_buckets(ax, x, y1, y2):
ax.clear()
ax.set_xticks(x, bucket_sizes, rotation='vertical')
ax.set_xlabel('Bucket Size (B)')
ax.set_ylabel('Total Memory Usage (MiB)')
ax.bar(x, y1, color='g', width=0.8)
ax.bar(x, y2, bottom=y1, color='plum', width=0.8)
ax.legend(handles=[green_patch, plum_patch])
plot_buckets(ax_a, x, ya1, ya2)
plot_buckets(ax_b, x, yb1, yb2)
# We want both plots to use the same y-height, so they can be compared
# easily just by looking at them.
h = max(ax.get_ylim() for ax in axes)
for ax in axes:
plt.setp(ax, ylim=h)
def show_title(ax, total_size):
diff = total_size - total_size_a
ax.set_title(
'Alternate Distribution uses an extra {:+.2f} KiB due to internal fragmentation ({:+.2%})'
.format(diff * KIB, diff / total_size_a),
size='medium')
plt.suptitle('Memory Usage v. Bucket Size', size='x-large', weight='bold')
show_title(ax_b, total_size_b)
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
main(argv)
|