15f9996aaSopenharmony_ci#!/usr/bin/env python 25f9996aaSopenharmony_ci# -*- coding: utf-8 -*- 35f9996aaSopenharmony_ci# Copyright (c) 2021 Huawei Device Co., Ltd. 45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License. 65f9996aaSopenharmony_ci# You may obtain a copy of the License at 75f9996aaSopenharmony_ci# 85f9996aaSopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 95f9996aaSopenharmony_ci# 105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software 115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and 145f9996aaSopenharmony_ci# limitations under the License. 155f9996aaSopenharmony_ci 165f9996aaSopenharmony_ciimport os 175f9996aaSopenharmony_ciimport sys 185f9996aaSopenharmony_ciimport json 195f9996aaSopenharmony_ciimport gzip 205f9996aaSopenharmony_ciimport shutil 215f9996aaSopenharmony_ciimport argparse 225f9996aaSopenharmony_ci 235f9996aaSopenharmony_ciKFILESIGNATURE = "# ninja log v5\n" 245f9996aaSopenharmony_ci 255f9996aaSopenharmony_ci 265f9996aaSopenharmony_ciclass StoringDataLine(object): 275f9996aaSopenharmony_ci def __init__(self, start, end): 285f9996aaSopenharmony_ci self.start = int(start) 295f9996aaSopenharmony_ci self.end = int(end) 305f9996aaSopenharmony_ci self.target_obj_names = [] 315f9996aaSopenharmony_ci 325f9996aaSopenharmony_ci def __str__(self): 335f9996aaSopenharmony_ci return "{} {} {} ".format(self.start, self.end, self.target_obj_names) 345f9996aaSopenharmony_ci 355f9996aaSopenharmony_ci 365f9996aaSopenharmony_ciclass NinjaToTrace(object): 375f9996aaSopenharmony_ci def __init__(self): 385f9996aaSopenharmony_ci self.datalist = list() 395f9996aaSopenharmony_ci self.durations = list() 405f9996aaSopenharmony_ci 415f9996aaSopenharmony_ci def parse_file(self, filename, ninja_start_time): 425f9996aaSopenharmony_ci # ensure file exist 435f9996aaSopenharmony_ci if not os.path.exists(filename): 445f9996aaSopenharmony_ci print("file: {} not exists".format(filename)) 455f9996aaSopenharmony_ci return False 465f9996aaSopenharmony_ci storing_data = {} 475f9996aaSopenharmony_ci with open(filename, mode='r') as f: 485f9996aaSopenharmony_ci firstline = f.readline() 495f9996aaSopenharmony_ci if firstline != KFILESIGNATURE: 505f9996aaSopenharmony_ci print("unrecognized ninja log format, we need {}".format( 515f9996aaSopenharmony_ci KFILESIGNATURE)) 525f9996aaSopenharmony_ci 535f9996aaSopenharmony_ci for _, line in enumerate(f.readlines()): 545f9996aaSopenharmony_ci start, end, time_stamp, name, cmdhash = line.strip().split( 555f9996aaSopenharmony_ci '\t') 565f9996aaSopenharmony_ci if time_stamp > ninja_start_time: 575f9996aaSopenharmony_ci storing_data.setdefault(cmdhash, StoringDataLine(start, end)) 585f9996aaSopenharmony_ci storing_data.get(cmdhash).target_obj_names.append(name) 595f9996aaSopenharmony_ci 605f9996aaSopenharmony_ci self.datalist = sorted(storing_data.values(), 615f9996aaSopenharmony_ci key=lambda line: line.start) 625f9996aaSopenharmony_ci self.durations = sorted(storing_data.values(), 635f9996aaSopenharmony_ci key=lambda line: line.end - line.start, 645f9996aaSopenharmony_ci reverse=True) 655f9996aaSopenharmony_ci return True 665f9996aaSopenharmony_ci 675f9996aaSopenharmony_ci def save_durations(self, duration_file: str): 685f9996aaSopenharmony_ci total_time = 0 695f9996aaSopenharmony_ci with open(duration_file, 'w') as file: 705f9996aaSopenharmony_ci for item in self.durations: 715f9996aaSopenharmony_ci duration = item.end - item.start 725f9996aaSopenharmony_ci total_time += duration 735f9996aaSopenharmony_ci file.write('{}: {}\n'.format(item.target_obj_names[0], 745f9996aaSopenharmony_ci duration)) 755f9996aaSopenharmony_ci file.write('total time: {} ms'.format(total_time)) 765f9996aaSopenharmony_ci 775f9996aaSopenharmony_ci def trans_to_trace_json(self, dest_file_name: str): 785f9996aaSopenharmony_ci counter = CountingTheTid() 795f9996aaSopenharmony_ci tracelist = list() 805f9996aaSopenharmony_ci for storingdataline in self.datalist: 815f9996aaSopenharmony_ci tracelist.append({ 825f9996aaSopenharmony_ci 'name': '%0s' % ', '.join(storingdataline.target_obj_names), 835f9996aaSopenharmony_ci 'cat': 'targets', 845f9996aaSopenharmony_ci 'ph': 'X', 855f9996aaSopenharmony_ci 'ts': str(storingdataline.start * 1000), 865f9996aaSopenharmony_ci 'dur': str((storingdataline.end - storingdataline.start) * 1000), 875f9996aaSopenharmony_ci 'pid': str(0), 885f9996aaSopenharmony_ci 'tid': str(counter.counting_the_new_tid(storingdataline)), 895f9996aaSopenharmony_ci 'args': {}, 905f9996aaSopenharmony_ci }) 915f9996aaSopenharmony_ci 925f9996aaSopenharmony_ci if not dest_file_name.endswith('.gz'): 935f9996aaSopenharmony_ci dest_file_name = dest_file_name + '.gz' 945f9996aaSopenharmony_ci 955f9996aaSopenharmony_ci if os.path.exists(dest_file_name): 965f9996aaSopenharmony_ci shutil.move( 975f9996aaSopenharmony_ci dest_file_name, '%s/build.trace.%d.gz' % 985f9996aaSopenharmony_ci (os.path.dirname(dest_file_name), 995f9996aaSopenharmony_ci int(os.stat(dest_file_name).st_mtime))) 1005f9996aaSopenharmony_ci 1015f9996aaSopenharmony_ci with gzip.open(dest_file_name, "wt") as f: 1025f9996aaSopenharmony_ci json.dump(tracelist, f) 1035f9996aaSopenharmony_ci 1045f9996aaSopenharmony_ci 1055f9996aaSopenharmony_ciclass CountingTheTid(object): 1065f9996aaSopenharmony_ci def __init__(self): 1075f9996aaSopenharmony_ci self.tids = [] # store the tid's end time 1085f9996aaSopenharmony_ci 1095f9996aaSopenharmony_ci def counting_the_new_tid(self, storingdataline): 1105f9996aaSopenharmony_ci for i, tid in enumerate(self.tids): 1115f9996aaSopenharmony_ci if tid <= storingdataline.start: 1125f9996aaSopenharmony_ci self.tids[i] = storingdataline.end 1135f9996aaSopenharmony_ci return i # renew the endtime and return the current tid 1145f9996aaSopenharmony_ci 1155f9996aaSopenharmony_ci # for the end time is newer than all tids so we need a new one 1165f9996aaSopenharmony_ci self.tids.append(storingdataline.end) 1175f9996aaSopenharmony_ci return len(self.tids) - 1 # the last index of the tids 1185f9996aaSopenharmony_ci 1195f9996aaSopenharmony_ci 1205f9996aaSopenharmony_cidef main(): 1215f9996aaSopenharmony_ci parser = argparse.ArgumentParser() 1225f9996aaSopenharmony_ci parser.add_argument('--ninja-log', help='path to ninja log') 1235f9996aaSopenharmony_ci parser.add_argument('--trace-file', help='path to build trace file') 1245f9996aaSopenharmony_ci parser.add_argument('--duration-file', help='path to duration file') 1255f9996aaSopenharmony_ci parser.add_argument( 1265f9996aaSopenharmony_ci '--ninja-start-time', 1275f9996aaSopenharmony_ci help='epoch time of "Starting ninja ..." in nanoseconds') 1285f9996aaSopenharmony_ci 1295f9996aaSopenharmony_ci options = parser.parse_args() 1305f9996aaSopenharmony_ci myparser = NinjaToTrace() 1315f9996aaSopenharmony_ci if not myparser.parse_file(options.ninja_log, options.ninja_start_time): 1325f9996aaSopenharmony_ci print("parse file fail") 1335f9996aaSopenharmony_ci return 1345f9996aaSopenharmony_ci 1355f9996aaSopenharmony_ci myparser.trans_to_trace_json(options.trace_file) 1365f9996aaSopenharmony_ci myparser.save_durations(options.duration_file) 1375f9996aaSopenharmony_ci 1385f9996aaSopenharmony_ci 1395f9996aaSopenharmony_ciif __name__ == '__main__': 1405f9996aaSopenharmony_ci sys.exit(main()) 141