1#!/usr/bin/env python3
2#
3# Copyright (C) 2023 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
17import sys
18
19from read_build_trace_gz import Trace
20
21
22
23
24def compare(target, target_name, ref, ref_name, ignore_text=None):
25    """Compares which modules are built additionally from the target compared to
26    the ref trace. It returns the additional modules sorted by the build time
27    duration.
28
29    Args:
30      target: Trace class, The build.trace.gz information of the target build.
31              It has duration dictionary of {module_name:duration}.
32      target_name: str, target name of the target build.
33      ref: Trace class, The build.trace.gz information of the reference build.
34      ref_name: str, target name of the reference build.
35    Returns:
36      list of (module, duration) pairs, sum of all durations
37    """
38    additional_modules = dict()
39    additional_time = 0
40
41    # Trace.duration is a dictionary of module_name:duration.
42    for mod in target.duration.keys():
43        if ignore_text and ignore_text in mod:
44            continue
45        if mod.replace(target_name, ref_name) not in ref.duration:
46            additional_modules[mod] = target.duration[mod]
47            additional_time += target.duration[mod]
48
49    return (sorted(additional_modules.items(), key=lambda x:x[1], reverse=True),
50            additional_time)
51
52def usec_to_min(usec):
53    min = usec // 60000000
54    sec = usec % 60000000 // 1000000
55    msec = usec % 1000000 // 1000
56    return (min, sec, msec)
57
58
59def main(argv):
60    # args: target_build.trace.gz target_name
61    #       ref_build.trace.gz ref_name
62    #       (ignore_text)
63    ignore_text = None
64    if len(argv) == 6:
65        ignore_text = argv[5]
66    elif len(argv) < 5 or len(argv) > 6:
67        print("usage: compare_build_trace.py target_build.trace.gz target_name")
68        print("                              ref_build.trace.gz ref_name")
69        print("                              [ignore_text]")
70        sys.exit(1)
71
72    additional_modules, additional_time = compare(Trace(argv[1]), argv[2],
73                                                  Trace(argv[3]), argv[4],
74                                                  ignore_text)
75    for module, duration in additional_modules:
76        min, sec, msec = usec_to_min(duration)
77        print('{min}m {sec}s {msec}ms: {name}'.format(
78            min=min, sec=sec, msec=msec, name=module))
79    min, sec, msec = usec_to_min(additional_time)
80    print('Total: {min}m {sec}s {msec}ms'.format(
81        min=min, sec=sec, msec=msec))
82
83if __name__ == '__main__':
84    main(sys.argv)