• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 
30 #include <malloc.h>
31 #include <stdio.h>
32 #include <time.h>
33 #include "stopwatch.h"
34 #include <math.h>
35 
36 #define SNPRINTF_OR_RETURN(str, size, format, ...) {                    \
37         int len = snprintf((str), (size), (format), ## __VA_ARGS__);    \
38         if (len < 0) return;                                            \
39         if (len > static_cast<int>(size)) {                             \
40             fprintf(stderr, "Not enough space\n");                      \
41             return;                                                     \
42         } else {                                                        \
43             (size) -= len; (str) += len;                                \
44         }                                                               \
45     }
46 
47 namespace {
48 const bool kVerbose = false;
49 bool printRaw = false;
50 }
51 
52 namespace android_test {
53 
StopWatch(const char * name,size_t capacity)54 StopWatch::StopWatch(const char *name, size_t capacity)
55     : mName(strdup(name)), mNum(0), mData(NULL), mDataLen(0), mCapacity(capacity * 2),
56       mSizeKbytes(0), mAlreadyPrinted(false), mPrintRaw(false),
57       mDuration(0.0), mDeviation(0.0),
58       mMinDuration(0.0), mMinIdx(0),
59       mMaxDuration(0.0), mMaxIdx(0),
60       mDeltas(NULL), mUsed(false)
61 {
62     mStart.tv_sec = 0;
63     mStart.tv_nsec = 0;
64     mData = (Measurement *) malloc(mCapacity * sizeof(Measurement));
65 }
66 
~StopWatch()67 StopWatch::~StopWatch()
68 {
69     if (mUsed && !mAlreadyPrinted)
70     {
71         fprintf(stderr, "Discarding data for %s\n", mName);
72     }
73     free(mData);
74     free(mName);
75     delete [] mDeltas;
76 }
77 
start()78 void StopWatch::start()
79 {
80     checkCapacity();
81     clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime);
82     mData[mDataLen].mIsStart = true;
83     if (!mUsed)
84     {
85         mStart = mData[mDataLen].mTime; // mDataLen should be 0
86         mUsed = true;
87     }
88     ++mNum;
89     ++mDataLen;
90 }
91 
stop()92 void StopWatch::stop()
93 {
94     checkCapacity();
95     clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime);
96     mData[mDataLen].mIsStart = false;
97     ++mDataLen;
98 }
99 
setPrintRawMode(bool raw)100 void StopWatch::setPrintRawMode(bool raw)
101 {
102     printRaw = raw;
103 }
104 
105 
sprint(char ** str,size_t * size)106 void StopWatch::sprint(char **str, size_t *size)
107 {
108     if (kVerbose) fprintf(stderr, "printing\n");
109     mAlreadyPrinted = true;
110     if (0 == mDataLen)
111     {
112         return;
113     }
114     if (mDataLen > 0 && mData[mDataLen - 1].mIsStart)
115     {
116         stop();
117     }
118     if (kVerbose) SNPRINTF_OR_RETURN(*str, *size, "# Got %d samples for %s\n", mDataLen, mName);
119     processSamples();
120 
121     SNPRINTF_OR_RETURN(*str, *size, "# StopWatch %s total/cumulative duration %f Samples: %d\n",
122                        mName, mDuration, mNum);
123     printThroughput(str, size);
124     printAverageMinMax(str, size);
125 
126     if (printRaw)
127     {
128         // print comment header and summary values.
129 
130         SNPRINTF_OR_RETURN(*str, *size, "# Name Iterations  Duration Min MinIdx Max MaxIdx SizeKbytes\n");
131         SNPRINTF_OR_RETURN(*str, *size, "%s %d %f %f %d %f %d %d\n", mName, mNum, mDuration,
132                            mMinDuration, mMinIdx, mMaxDuration, mMaxIdx, mSizeKbytes);
133         // print each duration sample
134         for (size_t i = 0; i < mDataLen / 2; ++i)
135         {
136             long second = mData[i * 2].mTime.tv_sec - mStart.tv_sec;
137             long nano = mData[i * 2].mTime.tv_nsec - mStart.tv_nsec;
138 
139             SNPRINTF_OR_RETURN(*str, *size, "%f %f\n", double(second) + double(nano) / 1.0e9, mDeltas[i]);
140         }
141     }
142 
143 }
144 
145 // Normally we should have enough capacity but if we have to
146 // reallocate the measurement buffer (e.g start and stop called more
147 // than once in an iteration) we let the user know. She should provide
148 // a capacity when building the StopWatch.
checkCapacity()149 void StopWatch::checkCapacity()
150 {
151     if (mDataLen >= mCapacity)
152     {
153         mCapacity *= 2;
154         fprintf(stderr, "# Increased capacity to %d for %s. Measurement affected.\n",
155                 mCapacity, mName);
156         mData = (Measurement *)realloc(mData, mCapacity * sizeof(Measurement));
157     }
158 }
159 
160 
161 // Go over all the samples and compute the diffs between a start and
162 // stop pair. The diff is accumulated in mDuration and inserted in
163 // mDeltas.
164 // The min and max values for a diff are also tracked.
processSamples()165 void StopWatch::processSamples()
166 {
167     if (kVerbose) fprintf(stderr, "processing samples\n");
168     size_t n = mDataLen / 2;
169     mDeltas= new double[n];
170     for (size_t i = 0; i < mDataLen; i += 2)   // even: start  odd: stop
171     {
172         long second = mData[i + 1].mTime.tv_sec - mData[i].mTime.tv_sec;
173         long nano = mData[i + 1].mTime.tv_nsec - mData[i].mTime.tv_nsec;
174 
175         mDeltas[i / 2] = double(second) + double(nano) / 1.0e9;
176     }
177 
178     for (size_t i = 0; i < n; ++i)
179     {
180         if (0 == i)
181         {
182             mMinDuration = mMaxDuration = mDeltas[i];
183         }
184         else
185         {
186             if (mMaxDuration < mDeltas[i])
187             {
188                 mMaxDuration = mDeltas[i];
189                 mMaxIdx = i;
190             }
191             if (mMinDuration > mDeltas[i])
192             {
193                 mMinDuration = mDeltas[i];
194                 mMinIdx = i;
195             }
196         }
197         mDuration += mDeltas[i];
198     }
199     double avgDuration = mDuration / n;
200     double diffSQ = 0.0;
201     for (size_t i = 0; i < n; ++i)
202     {
203       diffSQ += pow((mDeltas[i] - avgDuration), 2.0);
204     }
205     mDeviation = sqrt(diffSQ / n);
206 }
207 
208 
timespecToDouble(const struct timespec & time)209 double StopWatch::timespecToDouble(const struct timespec& time)
210 {
211     double val = double(time.tv_nsec) / 1.0e9 + double(time.tv_sec);
212     return val < 0.0 ? -val : val;  // sometimes 0.00 is -0.00
213 }
214 
215 
216 // If we have only 2 values, don't bother printing anything.
printAverageMinMax(char ** str,size_t * size)217 void StopWatch::printAverageMinMax(char **str, size_t *size)
218 {
219     if (mDataLen > 2) // if there is only one sample, avg, min, max are trivial.
220     {
221         SNPRINTF_OR_RETURN(*str, *size, "# Average %s duration %f s/op\n", mName, mDuration / mNum);
222         SNPRINTF_OR_RETURN(*str, *size, "# Standard deviation %s duration %f \n", mName, mDeviation);
223         SNPRINTF_OR_RETURN(*str, *size, "# Min %s duration %f [%d]\n", mName, mMinDuration, mMinIdx);
224         SNPRINTF_OR_RETURN(*str, *size, "# Max %s duration %f [%d]\n", mName, mMaxDuration, mMaxIdx);
225     }
226 }
227 
printThroughput(char ** str,size_t * size)228 void StopWatch::printThroughput(char **str, size_t *size)
229 {
230     if (0 != mSizeKbytes)
231     {
232         SNPRINTF_OR_RETURN(*str, *size, "# Size: %d Kbytes  Total: %d\n", mSizeKbytes, mNum);
233         SNPRINTF_OR_RETURN(*str, *size, "# Speed %f Kbyte/s\n", double(mSizeKbytes) * mNum / mDuration);
234     }
235 }
236 }  // namespace android_test
237