diff options
Diffstat (limited to 'perf_tools/progress_report.py')
-rwxr-xr-x | perf_tools/progress_report.py | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/perf_tools/progress_report.py b/perf_tools/progress_report.py new file mode 100755 index 00000000..f6a1c430 --- /dev/null +++ b/perf_tools/progress_report.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 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 +from datetime import datetime +import yaml +import os +import report_pb2 +import sys +import traceback + +# Usage: python3 progress_report.py --logcat logcat.txt --config config.yaml --output_dir report_dir +# +# logcat.txt should contain the "boot_progress_start" and "boot_progress_enable_screen"". +# config.yaml contains all the keywords to be extracted. +# report_dir will contain three generated files: +# +# timestamp_log.txt: contains the same content as logcat.txt, but the timestamp is replaced +# with relative time with boot_progress_start time. +# +# report_proto.txt: contains the report for the events related to the keywords. +# +# report.txt: contains logcat messages corresponding to the events captured in report_proto.txt + +def init_arguments(): + parser = argparse.ArgumentParser( + prog = 'progrocess_report.py', + description='Extract timing information and generate a report.') + parser.add_argument( + '--logcat', type=str, required=True, + help = 'logcat file name') + parser.add_argument( + '--config', type=str, required=True, + help = 'configuration file for keywords') + parser.add_argument( + '--output_dir', type= str, required=True, + help = 'directory name to store the generated files') + return parser.parse_args() + +# Find boot_progress_start line and boot_progress_enable_screen find the time difference +# return the start time string +def find_boot_progress_start_end(fp): + start = "" + end = "" + for line in fp: + if "boot_progress_start" in line: + start = line + if "boot_progress_enable_screen" in line and len(start): + end = line + break + + missing_error = "" + if start == "": + missing_error = "******logcat file missing boot_progress_start\n" + elif end == "": + missing_error += "******logcat file missing boot_progress_end " + if missing_error != "": + sys.exit("Missing required message in the logcat:\n" + missing_error) + return [start, end] + +# TODO(b/262259622): passing a tuple of (startDate, endDate) +def replace_timestamp_abs(line, timestamp_str, date_time_obj0): + index = line.find(" ", 6) + if index <= 0: + return line + substr0 = line[:index] + substr1 = line[index:] + + try: + date_time_obj = datetime.strptime(substr0, '%m-%d %H:%M:%S.%f') + except ValueError: + return line + + date_time_delta = date_time_obj - date_time_obj0 + date_time_delta_str = str(date_time_delta) + return date_time_delta_str + substr1 + +def in_time_range(start, end, line): + try: + current_time = datetime.strptime(line[:18], '%m-%d %H:%M:%S.%f') + except ValueError: + return False + + if current_time >= start and current_time <= end: + return True + + return False + +# Here is an example of event we would like extract: +# 09-15 16:04:15.655 root 991 991 I boot_progress_preload_start: 5440 +# for each event, it is a tuple of(timestamp, event_name, timing) +def extract_event(line, keywords): + words = line.split(" ") + for keyword in keywords: + if keyword in words[-2]: + return (words[0], words[-2], words[-1]) + return () + +def write_to_new_file(timestamps, keywords, logcat_fp, timestamp_fixed_logcat_fp, report_fp, + report_proto_fp): + start_timestamp_obj = datetime.strptime(timestamps[0][:18], '%m-%d %H:%M:%S.%f') + end_timestamp_obj = datetime.strptime(timestamps[1][:18], '%m-%d %H:%M:%S.%f') + report = report_pb2.Report() + for line in logcat_fp: + ts_fixed_line = replace_timestamp_abs(line, timestamps[0][:18], start_timestamp_obj) + timestamp_fixed_logcat_fp.write(ts_fixed_line) + if in_time_range(start_timestamp_obj, end_timestamp_obj, line): + event = extract_event(ts_fixed_line, keywords) + if len(event) == 0: + continue + + report_fp.write(ts_fixed_line) + record = report.record.add() + record.timestamp = event[0] + record.event = event[1] + record.timing = int(event[2]) + report_proto_fp.write(str(report)) + +def main(): + args = init_arguments() + + keywords = [] + with open(args.config, 'r') as file: + keywords = yaml.safe_load(file) + + if not os.path.isdir(args.output_dir): + os.mkdir(args.output_dir) + timestamp_fixed_logcat_fp = open(os.path.join(args.output_dir, "timestamp_fixed_log.txt"), 'w') + report_fp = open(os.path.join(args.output_dir, "report.txt"), 'w') + report_proto_fp = open(os.path.join(args.output_dir, "report_proto.txt"), 'w') + try: + with open(args.logcat, 'r', errors = 'ignore') as logcat_fp: + timestamps = find_boot_progress_start_end(logcat_fp) + logcat_fp.seek(0) + write_to_new_file(timestamps, keywords, logcat_fp, timestamp_fixed_logcat_fp, report_fp, report_proto_fp) + except Exception as e: + traceresult = traceback.format_exc() + print("Caught an exception: {}".format(traceback.format_exc())) + + timestamp_fixed_logcat_fp.close() + report_fp.close() + report_proto_fp.close() + +if __name__ == '__main__': + main() |