1#!/usr/bin/python3
2
3# Copyright (C) 2022 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18"""Tool to parse CarWatchdog's performance stats dump.
19
20To build the parser script run:
21  m perf_stats_parser
22
23To parse a carwatchdog dump text file run:
24  perf_stats_parser -f <cw-dump>.txt -o cw_proto_out.pb
25
26To read a carwatchdog proto file as a json run:
27  perf_stats_parser -r <cw-proto-out>.pb -j
28"""
29
30import argparse
31import json
32import os
33import sys
34
35from . import carwatchdog_dump_parser
36from . import perf_stats_proto_utils
37
38
39def init_arguments() -> argparse.Namespace:
40  """Initializes the program arguments."""
41  parser = argparse.ArgumentParser(description="Parses CarWatchdog's dump.")
42  parser.add_argument(
43      "-f",
44      "--file",
45      dest="file",
46      default="dump.txt",
47      help="File with the CarWatchdog dump",
48  )
49  parser.add_argument(
50      "-o",
51      "--out",
52      dest="out",
53      help="protobuf binary with parsed performance stats",
54  )
55  parser.add_argument(
56      "-b",
57      "--build",
58      dest="build",
59      help="File with Android device build information",
60  )
61  parser.add_argument(
62      "-d",
63      "--device-out",
64      dest="device_out",
65      default="device_perf_stats.pb",
66      help="protobuf binary with build information",
67  )
68  parser.add_argument(
69      "-p",
70      "--print",
71      dest="print",
72      action="store_true",
73      help=(
74          "prints the parsed performance data to the console "
75          "when out proto defined"
76      ),
77  )
78  parser.add_argument(
79      "-r",
80      "--read",
81      dest="read_proto",
82      help=(
83          "Protobuf binary to be printed in console. If this "
84          "flag is set no other process is executed."
85      ),
86  )
87  parser.add_argument(
88      "-D",
89      "--device-run",
90      dest="device_run",
91      action="store_true",
92      help=(
93          "Specifies that the proto to be read is a "
94          "DevicePerformanceStats proto. (Only checked if "
95          "-r is set)"
96      ),
97  )
98  parser.add_argument(
99      "-j",
100      "--json",
101      dest="json",
102      action="store_true",
103      help="Generate a JSON file from the protobuf binary read.",
104  )
105
106  return parser.parse_args()
107
108
109if __name__ == "__main__":
110  args = init_arguments()
111
112  if args.read_proto:
113    if not os.path.isfile(args.read_proto):
114      print("Error: Proto binary '%s' does not exist" % args.read_proto)
115      sys.exit(1)
116    if args.device_run:
117      performance_stats = (
118          perf_stats_proto_utils.read_device_performance_stats_pb(
119              args.read_proto
120          )
121      )
122    else:
123      performance_stats = perf_stats_proto_utils.read_performance_stats_pb(
124          args.read_proto
125      )
126    if performance_stats is None:
127      print(f"Error: Could not read '{args.read_proto}'")
128      sys.exit(1)
129    if args.json:
130      print(json.dumps(performance_stats.to_dict()))
131    else:
132      print(performance_stats)
133    sys.exit()
134
135  if not os.path.isfile(args.file):
136    print("Error: File '%s' does not exist" % args.file)
137    sys.exit(1)
138
139  with open(args.file, "r", encoding="UTF-8", errors="ignore") as f:
140    performance_stats = carwatchdog_dump_parser.parse_dump(f.read())
141
142    build_info = None
143    if args.build:
144      build_info = carwatchdog_dump_parser.parse_build_info(args.build)
145      print(build_info)
146
147    if performance_stats.is_empty():
148      print(
149          "Error: No performance stats were parsed. Make sure dump file"
150          " contains carwatchdog's dump text."
151      )
152      sys.exit(1)
153
154    if (args.out or args.build) and perf_stats_proto_utils.write_pb(
155        performance_stats, args.out, build_info, args.device_out
156    ):
157      out_file = args.out if args.out else args.device_out
158      print("Output protobuf binary in:", out_file)
159
160    if args.print or not (args.out or args.build):
161      if args.json:
162        print(json.dumps(performance_stats.to_dict()))
163        sys.exit()
164      print(performance_stats)
165