1 # This script filters the PERF traces based on the specified parameters and 2 # measures the rate of the filtered traces. This can be used to measure 3 # video encode/decode/preview frame rates. 4 # 5 # Fields in a PERF CSV line: 6 # 7 # $1 - time stamp 8 # $2 - PID 9 # $3 - address 10 # $4 - component 11 # $5-$10 - domains (AD, VD, ID, AE, VE, IE) 12 # $11 - component type 13 # $12 - operation 14 # $13-... operation specific arguments: 15 # Buffer: 16 # $13 - sending|received|xfering 17 # $14 - frame|buffer 18 # $15 - from 19 # $16 - to 20 # $17 - size 21 # $18 - address 1 22 # $19 - address 2 23 # Boundary: 24 # $13 - hex 25 # $14 - textual 26 27 # initialize variables 28 BEGIN { 29 FS = ","; # reading a CSV file 30 31 what = what ? what : "frame"; # what buffers are we looking at 32 how = how ? how : "sending"; # what is the operation 33 to = to ? to : ""; # who are the recipients of these buffers 34 from = from ? from : ""; # who are the senders of these buffers 35 36 # boundary - only log buffer traces in the steady state of this component 37 boundary = boundary ? boundary : "****"; 38 39 min = (size != "") ? (size) : (min != "") ? (min) : 1; # min size of buffers to watch 40 max = (size != "") ? (size) : (max != "") ? (max) : 5e9; # max size of buffers to watch 41 # Additional variables not set: 42 43 # debug - debug flag 44 # after - only measure frames after the specified # 45 # who - who is logging these buffer transfers 46 47 # get variable assignments from ARGV 48 for (i=1; i<ARGC; i++) { 49 arg = ARGV[i]; 50 if (gsub("^what=", "",arg)) { what = arg } 51 else if (gsub("^to=", "",arg)) { to = arg } 52 else if (gsub("^from=", "",arg)) { from = arg } 53 else if (gsub("^how=", "",arg)) { how = arg } 54 else if (gsub("^who=", "",arg)) { who = arg } 55 else if (gsub("^boundary=","",arg)) { boundary = arg } 56 else if (gsub("^after=", "",arg)) { after = arg } 57 else if (gsub("^debug=", "",arg)) { debug = arg } 58 else if (gsub("^size=", "",arg)) { min = max = (arg) } 59 else if (gsub("^min=", "",arg)) { min = (arg) } 60 else if (gsub("^max=", "",arg)) { max = (arg) } 61 62 else continue; 63 delete ARGV[i]; 64 } 65 66 if (!who) { 67 print "Must specify component to observe"; 68 exit 1; 69 } 70 71 # we are using the component thread as boundary by default 72 if (boundary == "****") { 73 if (substr(who, 0, 3) == "VP_" || 74 substr(who, 0, 3) == "VD_" || 75 substr(who, 0, 3) == "VE_" || 76 substr(who, 0, 3) == "CAM") { 77 boundary = substr(who, 0, 3) "T"; 78 } 79 } 80 81 after++; # we always have to after the 1st time stamp to get a time delta 82 skip = after + 1; 83 84 # start counting unless boundary is set, in which case 85 count = boundary ? skip : 0; 86 87 # initialize counters 88 x = xx = N = 0; 89 x_no_pause = xx_no_pause = N_no_pause = 0; 90 91 if (debug > 1) { 92 print "who = ", who 93 print "how = ", how 94 print "what = ", what 95 print "from = ", (from ? from : "UNDEFINED") 96 print "to = ", (to ? to : "UNDEFINED") 97 print "min = ", min 98 print "max = ", max 99 } 100 101 # convert to decimal 102 min = min + 0 103 max = max + 0 104 } 105 106 # Check for non-CSV trace file 107 /^</ { 108 print "ERROR: non-CSV file encountered. Please use csv = 1 in ./perf.ini"; 109 exit; 110 } 111 112 # Count frames 113 # frames start with a number, with operation "Buffer" 114 /^[0-9]/ && $4 == who && $12 == "Buffer" && 115 # how and what has to match 116 # if from or to are specified they also have to match 117 $13 == how && $14 == what && (!from || ($15 == from)) && (!to || ($16 == to)) && 118 # size has to fall in the range specified, we have to add 0 because of a 119 # rare rounding issue in AWK when comparing hex and decimal numbers 120 ((0 + $17) >= min) && 121 ((0 + $17) <= max) { 122 # debug 123 if (debug) { print $0 } 124 125 # increase the count from the boundary 126 if (count == after) { 127 delta = $1 - last; 128 if (delta >= 2) { 129 print "Warning: Found a pause of", delta, "seconds"; 130 } 131 else 132 { 133 x_no_pause += delta; 134 xx_no_pause += delta * delta; 135 N_no_pause++; 136 } 137 x += delta; 138 xx += delta * delta; 139 N++; 140 } 141 if (count < after) { count++; } 142 last = $1; 143 } 144 145 # Check boundaries 146 /Steady/ && $12 == "Boundary" && $4 == boundary { 147 # debug 148 if (debug) { print $0 } 149 150 # start counting if starting steady state, skip counting if ending steady 151 # state 152 count = /started/ ? 0 : skip; 153 } 154 155 END { 156 # calculate inverse (1/x) average and variance 157 if (N) { 158 x /= N; 159 xx /= N; 160 s = xx ? (x * x / xx) : 0; 161 result = 1/x " fps (s=" s ") (from " N " data points)"; 162 print "Rate is", result; 163 164 if (N != N_no_pause) { 165 if (N_no_pause) { 166 x = x_no_pause / N_no_pause; 167 xx = xx_no_pause / N_no_pause; 168 s = xx ? (x * x / xx) : 1; 169 result = 1/x " fps (s=" s ") (from " N " data points)"; 170 print "(Adjusted rate without pauses is", result, ")"; 171 } else { 172 print "(Not enough data to calculate adjusted rate without pauses)"; 173 } 174 } 175 } else { 176 print "Error: Not enough data to calculate rate"; 177 } 178 } 179 180