1# Copyright 2024 Google LLC 2# 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import json 7import sys 8 9trace_output = sys.argv[1] 10with open(trace_output, 'r') as f: 11 trace_json = json.load(f) 12output_json_file = sys.argv[2] 13renderer = sys.argv[3] # Unused for now but might be useful in the future. 14 15# Output data about the GPU that was used. 16print('GPU data:') 17print(trace_json['metadata'].get('gpu-gl-renderer')) 18print(trace_json['metadata'].get('gpu-driver')) 19print(trace_json['metadata'].get('gpu-gl-vendor')) 20 21erroneous_termination_statuses = [ 22 'replaced_by_new_reporter_at_same_stage', 23 'did_not_produce_frame', 24] 25accepted_termination_statuses = [ 26 'missed_frame', 27 'submitted_frame', 28 'main_frame_aborted' 29] 30 31current_frame_duration = 0 32total_frames = 0 33frame_id_to_start_ts = {} 34# Will contain tuples of frame_ids and their duration and status. 35completed_frame_id_and_duration_status = [] 36# Will contain tuples of drawn frame_ids and their duration. 37drawn_frame_id_and_duration = [] 38for trace in trace_json['traceEvents']: 39 if 'PipelineReporter' in trace['name']: 40 frame_id = trace['id'] 41 args = trace.get('args') 42 if args and args.get('step') == 'BeginImplFrameToSendBeginMainFrame': 43 frame_id_to_start_ts[frame_id] = trace['ts'] 44 elif args and (args.get('termination_status') in 45 accepted_termination_statuses): 46 if not frame_id_to_start_ts.get(frame_id): 47 print('[No start ts found for %s]' % frame_id) 48 continue 49 current_frame_duration = trace['ts'] - frame_id_to_start_ts[frame_id] 50 total_frames += 1 51 completed_frame_id_and_duration_status.append( 52 (frame_id, current_frame_duration, args['termination_status'])) 53 if(args['termination_status'] == 'missed_frame' or 54 args['termination_status'] == 'submitted_frame'): 55 drawn_frame_id_and_duration.append((frame_id, current_frame_duration)) 56 57 # We are done with this frame_id so remove it from the dict. 58 frame_id_to_start_ts.pop(frame_id) 59 print('%d (%s with %s): %d' % ( 60 total_frames, frame_id, args['termination_status'], 61 current_frame_duration)) 62 elif args and (args.get('termination_status') in 63 erroneous_termination_statuses): 64 # Invalidate previously collected results for this frame_id. 65 if frame_id_to_start_ts.get(frame_id): 66 print('[Invalidating %s due to %s]' % ( 67 frame_id, args['termination_status'])) 68 frame_id_to_start_ts.pop(frame_id) 69 70# Calculate metrics for total completed frames. 71total_completed_frames = len(completed_frame_id_and_duration_status) 72if total_completed_frames < 25: 73 raise Exception('Even with 3 loops found only %d frames' % 74 total_completed_frames) 75# Get frame avg/min/max for the middle 25 frames. 76start = (total_completed_frames - 25) // 2 77print('Got %d total completed frames. Using indexes [%d, %d).' % ( 78 total_completed_frames, start, start+25)) 79frame_max = 0 80frame_min = 0 81frame_cumulative = 0 82aborted_frames = 0 83for frame_id, duration, status in ( 84 completed_frame_id_and_duration_status[start:start+25]): 85 frame_max = max(frame_max, duration) 86 frame_min = min(frame_min, duration) if frame_min else duration 87 frame_cumulative += duration 88 if status == 'main_frame_aborted': 89 aborted_frames += 1 90 91perf_results = {} 92perf_results['frame_max_us'] = frame_max 93perf_results['frame_min_us'] = frame_min 94perf_results['frame_avg_us'] = frame_cumulative/25 95perf_results['aborted_frames'] = aborted_frames 96 97# Now calculate metrics for only drawn frames. 98drawn_frame_max = 0 99drawn_frame_min = 0 100drawn_frame_cumulative = 0 101total_drawn_frames = len(drawn_frame_id_and_duration) 102if total_drawn_frames < 25: 103 raise Exception('Even with 3 loops found only %d drawn frames' % 104 total_drawn_frames) 105# Get drawn frame avg/min/max from the middle 25 frames. 106start = (total_drawn_frames - 25) // 2 107print('Got %d total drawn frames. Using indexes [%d-%d).' % ( 108 total_drawn_frames, start, start+25)) 109for frame_id, duration in drawn_frame_id_and_duration[start:start+25]: 110 drawn_frame_max = max(drawn_frame_max, duration) 111 drawn_frame_min = (min(drawn_frame_min, duration) 112 if drawn_frame_min else duration) 113 drawn_frame_cumulative += duration 114# Add metrics to perf_results. 115perf_results['drawn_frame_max_us'] = drawn_frame_max 116perf_results['drawn_frame_min_us'] = drawn_frame_min 117perf_results['drawn_frame_avg_us'] = drawn_frame_cumulative/25 118 119print('Final perf_results dict: %s' % perf_results) 120 121# Write perf_results to the output json. 122with open(output_json_file, 'w') as f: 123 f.write(json.dumps(perf_results)) 124