| #!/usr/bin/env python3 |
| # |
| # Copyright 2020, The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import argparse |
| import os |
| import sys |
| from typing import Dict, List, NamedTuple, Tuple |
| |
| DIR = os.path.abspath(os.path.dirname(__file__)) |
| sys.path.append(os.path.dirname(DIR)) # framework/base/startop/script |
| import lib.print_utils as print_utils |
| |
| # Include generated protos. |
| dir_name = os.path.dirname(os.path.realpath(__file__)) |
| sys.path.append(dir_name + "/generated") |
| |
| from TraceFile_pb2 import * |
| |
| def parse_options(argv: List[str] = None): |
| """Parses command line arguments and returns an argparse Namespace object.""" |
| parser = argparse.ArgumentParser(description="Analyze compiled_trace iorap protos.") |
| required_named = parser.add_argument_group('required named arguments') |
| |
| required_named.add_argument('-i', dest='input', metavar='FILE', |
| help='Read protobuf file as input') |
| |
| optional_named = parser.add_argument_group('optional named arguments') |
| |
| optional_named.add_argument('-up', dest='upper_percent', type=float, |
| default=95.0, |
| help='Only show the top-most entries up to this value.') |
| |
| optional_named.add_argument('-r', dest='raw', action='store_true', |
| help='Output entire raw file.') |
| optional_named.add_argument('-o', dest='output', |
| help='The results are stored into the output file') |
| optional_named.add_argument('-d', dest='debug', action='store_true' |
| , help='Activity of the app to be compiled') |
| |
| return parser.parse_args(argv) |
| |
| def open_iorap_prefetch_file(file_path: str) -> TraceFile: |
| with open(file_path, "rb") as f: |
| tf = TraceFile() |
| tf.ParseFromString(f.read()) |
| return tf |
| |
| def print_stats_summary(trace_file: TraceFile, upper_percent): |
| tf_dict = convert_to_dict(trace_file) |
| print_utils.debug_print(tf_dict) |
| |
| total_length = 0 |
| summaries = [] |
| for name, entries_list in tf_dict.items(): |
| summary = entries_sum(entries_list) |
| summaries.append(summary) |
| |
| total_length += summary.length |
| |
| # Sort by length |
| summaries.sort(reverse=True, key=lambda s: s.length) |
| |
| percent_sum = 0.0 |
| skipped_entries = 0 |
| |
| print("===========================================") |
| print("Total length: {:,} bytes".format(total_length)) |
| print("Displayed upper percent: {:0.2f}%".format(upper_percent)) |
| print("===========================================") |
| print("") |
| print("name,length,percent_of_total,upper_percent") |
| for sum in summaries: |
| percent_of_total = (sum.length * 1.0) / (total_length * 1.0) * 100.0 |
| |
| percent_sum += percent_of_total |
| |
| if percent_sum > upper_percent: |
| skipped_entries = skipped_entries + 1 |
| continue |
| |
| #print("%s,%d,%.2f%%" %(sum.name, sum.length, percent_of_total)) |
| print("{:s},{:d},{:0.2f}%,{:0.2f}%".format(sum.name, sum.length, percent_of_total, percent_sum)) |
| |
| if skipped_entries > 0: |
| print("[WARNING] Skipped {:d} entries, use -up=100 to show everything".format(skipped_entries)) |
| |
| pass |
| |
| class FileEntry(NamedTuple): |
| id: int |
| name: str |
| offset: int |
| length: int |
| |
| class FileEntrySummary(NamedTuple): |
| name: str |
| length: int |
| |
| def entries_sum(entries: List[FileEntry]) -> FileEntrySummary: |
| if not entries: |
| return None |
| |
| summary = FileEntrySummary(name=entries[0].name, length=0) |
| for entry in entries: |
| summary = FileEntrySummary(summary.name, summary.length + entry.length) |
| |
| return summary |
| |
| def convert_to_dict(trace_file: TraceFile) -> Dict[str, FileEntry]: |
| trace_file_index = trace_file.index |
| |
| # entries.id -> entry.file_name |
| entries_map = {} |
| |
| index_entries = trace_file_index.entries |
| for entry in index_entries: |
| entries_map[entry.id] = entry.file_name |
| |
| final_map = {} |
| |
| file_entries_map = {} |
| file_entries = trace_file.list.entries |
| for entry in file_entries: |
| print_utils.debug_print(entry) |
| |
| lst = file_entries_map.get(entry.index_id, []) |
| file_entries_map[entry.index_id] = lst |
| |
| file_name = entries_map[entry.index_id] |
| file_entry = \ |
| FileEntry(id=entry.index_id, name=file_name, offset=entry.file_offset, length=entry.file_length) |
| |
| lst.append(file_entry) |
| |
| final_map[file_name] = lst |
| |
| return final_map |
| |
| def main(argv: List[str]) -> int: |
| opts = parse_options(argv[1:]) |
| if opts.debug: |
| print_utils.DEBUG = opts.debug |
| print_utils.debug_print(opts) |
| |
| prefetch_file = open_iorap_prefetch_file(opts.input) |
| |
| if opts.raw: |
| print(prefetch_file) |
| |
| print_stats_summary(prefetch_file, opts.upper_percent) |
| |
| return 0 |
| |
| if __name__ == '__main__': |
| sys.exit(main(sys.argv)) |