1 /*
2  * Copyright 2012 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 #include "TimerData.h"
8 
9 #include "Timer.h"
10 #include <limits>
11 
TimerData(int maxNumTimings)12 TimerData::TimerData(int maxNumTimings)
13     : fMaxNumTimings(maxNumTimings)
14     , fCurrTiming(0)
15     , fWallTimes(maxNumTimings)
16     , fTruncatedWallTimes(maxNumTimings)
17     , fCpuTimes(maxNumTimings)
18     , fTruncatedCpuTimes(maxNumTimings)
19     , fGpuTimes(maxNumTimings) {}
20 
appendTimes(Timer * timer)21 bool TimerData::appendTimes(Timer* timer) {
22     SkASSERT(timer != NULL);
23     if (fCurrTiming >= fMaxNumTimings) {
24         return false;
25     }
26 
27     fWallTimes[fCurrTiming] = timer->fWall;
28     fTruncatedWallTimes[fCurrTiming] = timer->fTruncatedWall;
29     fCpuTimes[fCurrTiming] = timer->fCpu;
30     fTruncatedCpuTimes[fCurrTiming] = timer->fTruncatedCpu;
31     fGpuTimes[fCurrTiming] = timer->fGpu;
32 
33     ++fCurrTiming;
34 
35     return true;
36 }
37 
getResult(const char * doubleFormat,Result result,const char * configName,uint32_t timerFlags,int itersPerTiming)38 SkString TimerData::getResult(const char* doubleFormat,
39                               Result result,
40                               const char *configName,
41                               uint32_t timerFlags,
42                               int itersPerTiming) {
43     SkASSERT(itersPerTiming >= 1);
44 
45     if (!fCurrTiming) {
46         return SkString("");
47     }
48 
49     int numTimings = fCurrTiming;
50 
51     SkString wallStr(" msecs = ");
52     SkString truncWallStr(" Wmsecs = ");
53     SkString cpuStr(" cmsecs = ");
54     SkString truncCpuStr(" Cmsecs = ");
55     SkString gpuStr(" gmsecs = ");
56 
57     double wallMin = std::numeric_limits<double>::max();
58     double truncWallMin = std::numeric_limits<double>::max();
59     double cpuMin = std::numeric_limits<double>::max();
60     double truncCpuMin = std::numeric_limits<double>::max();
61     double gpuMin = std::numeric_limits<double>::max();
62 
63     double wallSum = 0;
64     double truncWallSum = 0;
65     double cpuSum = 0;
66     double truncCpuSum = 0;
67     double gpuSum = 0;
68 
69     for (int i = 0; i < numTimings; ++i) {
70         if (kPerIter_Result == result) {
71             wallStr.appendf(doubleFormat, fWallTimes[i] / itersPerTiming);
72             truncWallStr.appendf(doubleFormat, fTruncatedWallTimes[i] / itersPerTiming);
73             cpuStr.appendf(doubleFormat, fCpuTimes[i] / itersPerTiming);
74             truncCpuStr.appendf(doubleFormat, fTruncatedCpuTimes[i] / itersPerTiming);
75             gpuStr.appendf(doubleFormat, fGpuTimes[i] / itersPerTiming);
76 
77             if (i != numTimings - 1) {
78                 static const char kSep[] = ", ";
79                 wallStr.append(kSep);
80                 truncWallStr.append(kSep);
81                 cpuStr.append(kSep);
82                 truncCpuStr.append(kSep);
83                 gpuStr.append(kSep);
84             }
85         } else if (kMin_Result == result) {
86             wallMin = SkTMin(wallMin, fWallTimes[i]);
87             truncWallMin = SkTMin(truncWallMin, fTruncatedWallTimes[i]);
88             cpuMin = SkTMin(cpuMin, fCpuTimes[i]);
89             truncCpuMin = SkTMin(truncCpuMin, fTruncatedCpuTimes[i]);
90             gpuMin = SkTMin(gpuMin, fGpuTimes[i]);
91         } else {
92             SkASSERT(kAvg_Result == result);
93             wallSum += fWallTimes[i];
94             truncWallSum += fTruncatedWallTimes[i];
95             cpuSum += fCpuTimes[i];
96             truncCpuSum += fTruncatedCpuTimes[i];
97         }
98 
99         // We always track the GPU sum because whether it is non-zero indicates if valid gpu times
100         // were recorded at all.
101         gpuSum += fGpuTimes[i];
102     }
103 
104     if (kMin_Result == result) {
105         wallStr.appendf(doubleFormat, wallMin / itersPerTiming);
106         truncWallStr.appendf(doubleFormat, truncWallMin / itersPerTiming);
107         cpuStr.appendf(doubleFormat, cpuMin / itersPerTiming);
108         truncCpuStr.appendf(doubleFormat, truncCpuMin / itersPerTiming);
109         gpuStr.appendf(doubleFormat, gpuMin / itersPerTiming);
110     } else if (kAvg_Result == result) {
111         int divisor = numTimings * itersPerTiming;
112         wallStr.appendf(doubleFormat, wallSum / divisor);
113         truncWallStr.appendf(doubleFormat, truncWallSum / divisor);
114         cpuStr.appendf(doubleFormat, cpuSum / divisor);
115         truncCpuStr.appendf(doubleFormat, truncCpuSum / divisor);
116         gpuStr.appendf(doubleFormat, gpuSum / divisor);
117     }
118 
119     SkString str;
120     str.printf("  %4s:", configName);
121     if (timerFlags & kWall_Flag) {
122         str += wallStr;
123     }
124     if (timerFlags & kTruncatedWall_Flag) {
125         str += truncWallStr;
126     }
127     if (timerFlags & kCpu_Flag) {
128         str += cpuStr;
129     }
130     if (timerFlags & kTruncatedCpu_Flag) {
131         str += truncCpuStr;
132     }
133     if ((timerFlags & kGpu_Flag) && gpuSum > 0) {
134         str += gpuStr;
135     }
136     return str;
137 }
138 
getJSON(uint32_t timerFlags,Result result,int itersPerTiming)139 Json::Value TimerData::getJSON(uint32_t timerFlags,
140                                Result result,
141                                int itersPerTiming) {
142     SkASSERT(itersPerTiming >= 1);
143     Json::Value dataNode;
144     Json::Value wallNode, truncWall, cpuNode, truncCpu, gpuNode;
145     if (!fCurrTiming) {
146         return dataNode;
147     }
148 
149     int numTimings = fCurrTiming;
150 
151     double wallMin = std::numeric_limits<double>::max();
152     double truncWallMin = std::numeric_limits<double>::max();
153     double cpuMin = std::numeric_limits<double>::max();
154     double truncCpuMin = std::numeric_limits<double>::max();
155     double gpuMin = std::numeric_limits<double>::max();
156 
157     double wallSum = 0;
158     double truncWallSum = 0;
159     double cpuSum = 0;
160     double truncCpuSum = 0;
161     double gpuSum = 0;
162 
163     for (int i = 0; i < numTimings; ++i) {
164         if (kPerIter_Result == result) {
165             wallNode.append(fWallTimes[i] / itersPerTiming);
166             truncWall.append(fTruncatedWallTimes[i] / itersPerTiming);
167             cpuNode.append(fCpuTimes[i] / itersPerTiming);
168             truncCpu.append(fTruncatedCpuTimes[i] / itersPerTiming);
169             gpuNode.append(fGpuTimes[i] / itersPerTiming);
170         } else if (kMin_Result == result) {
171             wallMin = SkTMin(wallMin, fWallTimes[i]);
172             truncWallMin = SkTMin(truncWallMin, fTruncatedWallTimes[i]);
173             cpuMin = SkTMin(cpuMin, fCpuTimes[i]);
174             truncCpuMin = SkTMin(truncCpuMin, fTruncatedCpuTimes[i]);
175             gpuMin = SkTMin(gpuMin, fGpuTimes[i]);
176         } else {
177             SkASSERT(kAvg_Result == result);
178             wallSum += fWallTimes[i];
179             truncWallSum += fTruncatedWallTimes[i];
180             cpuSum += fCpuTimes[i];
181             truncCpuSum += fTruncatedCpuTimes[i];
182         }
183 
184         // We always track the GPU sum because whether it is non-zero indicates if valid gpu times
185         // were recorded at all.
186         gpuSum += fGpuTimes[i];
187     }
188 
189     if (kMin_Result == result) {
190         wallNode.append(wallMin / itersPerTiming);
191         truncWall.append(truncWallMin / itersPerTiming);
192         cpuNode.append(cpuMin / itersPerTiming);
193         truncCpu.append(truncCpuMin / itersPerTiming);
194         gpuNode.append(gpuMin / itersPerTiming);
195     } else if (kAvg_Result == result) {
196         int divisor = numTimings * itersPerTiming;
197         wallNode.append(wallSum / divisor);
198         truncWall.append(truncWallSum / divisor);
199         cpuNode.append(cpuSum / divisor);
200         truncCpu.append(truncCpuSum / divisor);
201         gpuNode.append(gpuSum / divisor);
202     }
203 
204     if (timerFlags & kWall_Flag) {
205         dataNode["wall"] = wallNode;
206     }
207     if (timerFlags & kTruncatedWall_Flag) {
208         dataNode["truncWall"] = truncWall;
209     }
210     if (timerFlags & kCpu_Flag) {
211         dataNode["cpu"] = cpuNode;
212     }
213     if (timerFlags & kTruncatedCpu_Flag) {
214         dataNode["trucCpu"] = truncCpu;
215     }
216     if ((timerFlags & kGpu_Flag) && gpuSum > 0) {
217         dataNode["gpu"] = gpuNode;
218     }
219     return dataNode;
220 }
221