910e62b5创建于 1月15日历史提交
# 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)