# 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."""


from __future__ import print_function
import json
import os
import subprocess
import sys


def main():
  # This should be the stripped file from
  # out/android_release/lib.stripped/libflutter.so
  stripped_file = sys.argv[1]
  out_dir = sys.argv[2]
  keystr = sys.argv[3]
  propstr = sys.argv[4]
  bloaty_path = sys.argv[5]
  # This is the unstripped out/android_release/libflutter.so
  # The symbols in it are needed to get the compileunits data.
  symbols_file = sys.argv[6]
  config = sys.argv[7]
  total_size_bytes_key = sys.argv[8]
  lib_name = sys.argv[9]
  magic_seperator = sys.argv[10]

  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]

  # 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, stripped_file,
                                 '-d', 'compileunits,symbols', '-s', 'file',
                                 '-n', '0', '--tsv', '--demangle=short',
                                 '--debug-file=%s' % symbols_file])
  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, stripped_file,
                                 '-d', 'compileunits,symbols', '-s', 'file',
                                 '-n', '0', '--tsv', '--demangle=full',
                                 '--debug-file=%s' % symbols_file])
  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, stripped_file,
                                 '-d', 'symbols,compileunits', '-s', 'file',
                                 '-n', '0', '--tsv', '--demangle=short',
                                 '--debug-file=%s' % symbols_file])
  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, stripped_file,
                                 '-d', 'symbols,compileunits', '-s', 'file',
                                 '-n', '0', '--tsv', '--demangle=full',
                                 '--debug-file=%s' % symbols_file])
  print_skia_lines_symbol_file(lines)
  print(magic_seperator)

  r = {
    # Use the default config as stats about the whole binary
    config : {
      total_size_bytes_key: grand_total
    },
  }

  results['results'][lib_name] = r

  # Make debugging easier
  print(json.dumps(results, indent=2))

  with open(os.path.join(out_dir, lib_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 __name__ == '__main__':
  main()
