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
28BEGIN {
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
155END {
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