Track Skia's Code size in Flutter

This creates a nice readable display, since Bloaty
doesn't allow filtering through the CLI.

Additionally, rename the flutter job to accurately
represent what settings it actually is (32 bit ARM built
with clang).

Bug: skia:
Change-Id: Iaed313caf43a31105adc8c85c545cc6cb2bcbe30
Reviewed-on: https://skia-review.googlesource.com/c/160920
Reviewed-by: Mike Klein <mtklein@google.com>
Reviewed-by: Eric Boren <borenet@google.com>
Commit-Queue: Kevin Lubick <kjlubick@google.com>
diff --git a/infra/bots/buildstats/buildstats_flutter.py b/infra/bots/buildstats/buildstats_flutter.py
new file mode 100644
index 0000000..764c71b
--- /dev/null
+++ b/infra/bots/buildstats/buildstats_flutter.py
@@ -0,0 +1,151 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Writes a Perf-formated json file with stats about Skia's size in flutter."""
+
+
+import json
+import os
+import subprocess
+import sys
+
+
+def main():
+  input_file = sys.argv[1]
+  out_dir = sys.argv[2]
+  keystr = sys.argv[3]
+  propstr = sys.argv[4]
+  bloaty_path = sys.argv[5]
+
+  results = {
+    'key': { },
+    'results': { }
+  }
+
+  props = propstr.split(' ')
+  for i in range(0, len(props), 2):
+    results[props[i]] = props[i+1]
+
+  keys = keystr.split(' ')
+  for i in range(0, len(keys), 2):
+    results['key'][keys[i]] = keys[i+1]
+
+  magic_seperator = '#$%^&*'
+
+  # Human "readable" reports as an FYI.
+  print magic_seperator
+  print 'Report by file, then by symbol with ellided/combined templates'
+  lines = subprocess.check_output([bloaty_path, input_file,
+                                 '-d', 'compileunits,symbols', '-s', 'file',
+                                 '-n', '0', '--tsv', '--demangle=short'])
+  grand_total = print_skia_lines_file_symbol(lines)
+  print magic_seperator
+  print 'Report by file, then by symbol with full templates'
+  lines = subprocess.check_output([bloaty_path, input_file,
+                                 '-d', 'compileunits,symbols', '-s', 'file',
+                                 '-n', '0', '--tsv', '--demangle=full'])
+  print_skia_lines_file_symbol(lines)
+  print magic_seperator
+
+  print 'Report by symbol, then by file with ellided/combined templates'
+  lines = subprocess.check_output([bloaty_path, input_file,
+                                 '-d', 'symbols,compileunits', '-s', 'file',
+                                 '-n', '0', '--tsv', '--demangle=short'])
+  print_skia_lines_symbol_file(lines)
+  print magic_seperator
+
+  print 'Report by symbol, then by file with full templates'
+  lines = subprocess.check_output([bloaty_path, input_file,
+                                 '-d', 'symbols,compileunits', '-s', 'file',
+                                 '-n', '0', '--tsv', '--demangle=full'])
+  print_skia_lines_symbol_file(lines)
+  print magic_seperator
+
+  r = {
+    # Use the default config as stats about the whole binary
+    'skia_in_flutter' : {
+      'total_size_bytes': grand_total
+    },
+  }
+
+  name = os.path.basename(input_file)
+  results['results'][name] = r
+
+  # Make debugging easier
+  print json.dumps(results, indent=2)
+
+  with open(os.path.join(out_dir, name+'.json'), 'w') as output:
+    output.write(json.dumps(results, indent=2))
+
+
+def bytes_or_kb(num):
+  if num < 1024:
+    return '%d bytes' % num
+  else:
+    return '%1.1f KiB' % (num / 1024.0)
+
+
+def print_skia_lines_file_symbol(lines):
+  lines = lines.split('\n')
+  grand_total = 0
+  sub_total = 0
+  cur_file = ''
+
+  for line in lines:
+    # Line looks like:
+    # ../../third_party/skia/src/file.cpp\tSkTSect<>::intersects()\t1224\t1348
+    parts = line.split('\t')
+    if len(parts) != 4:
+      continue
+    this_file = parts[0]
+    if 'third_party/skia' not in this_file:
+      continue
+    symbol    = parts[1]
+    if '.debug' in symbol:
+      continue
+    # vmsize    = parts[2] Not needed
+    filesize  = int(parts[3])
+
+    if this_file != cur_file:
+      if cur_file != '':
+        print '\t%-100s: %s' % ('Total File Size', bytes_or_kb(sub_total))
+      sub_total = 0
+      cur_file = this_file
+      print this_file.replace('../../third_party/skia', 'skia')
+
+    print '\t%-100s: %s' % (symbol, bytes_or_kb(filesize))
+    sub_total += filesize
+    grand_total += filesize
+
+  print '\t%-100s: %s' % ('Total File Size', bytes_or_kb(sub_total))
+  print '======================================='
+  print 'Grand Total File Size: %s' % bytes_or_kb(grand_total)
+  return grand_total
+
+
+def print_skia_lines_symbol_file(lines):
+  lines = lines.split('\n')
+
+  for line in lines:
+    # Line looks like:
+    # SkTSect<>::intersects()\t../../third_party/skia/src/file.cpp\t1224\t1348
+    parts = line.split('\t')
+    if len(parts) != 4:
+      continue
+    symbol    = parts[0]
+    if 'section' in symbol:
+      continue
+    this_file = parts[1]
+    if 'third_party/skia' not in this_file:
+      continue
+    this_file = this_file.replace('../../third_party/skia', 'skia')
+    # vmsize    = parts[2] Not needed
+    filesize  = int(parts[3])
+
+    print '%-10s: %-80s in %s' % (bytes_or_kb(filesize), symbol, this_file)
+
+
+if '__main__' == __name__:
+  main()