blob: 77768d69c08b99d96dc030b0bd5be553469b9f20 [file] [log] [blame]
Nicolas Catania39c016f2009-05-18 16:08:12 -07001/*
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"
Xia Wangb0ba9852009-11-19 16:28:25 -080034#include <math.h>
Nicolas Catania39c016f2009-05-18 16:08:12 -070035
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
47namespace {
48const bool kVerbose = false;
49bool printRaw = false;
50}
51
52namespace android_test {
53
54StopWatch::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),
Xia Wangb0ba9852009-11-19 16:28:25 -080057 mDuration(0.0), mDeviation(0.0),
Nicolas Catania39c016f2009-05-18 16:08:12 -070058 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
67StopWatch::~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
78void 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
92void StopWatch::stop()
93{
94 checkCapacity();
95 clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime);
96 mData[mDataLen].mIsStart = false;
97 ++mDataLen;
98}
99
100void StopWatch::setPrintRawMode(bool raw)
101{
102 printRaw = raw;
103}
104
105
106void 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
Nicolas Cataniad6079c62009-06-03 11:08:47 -0700121 SNPRINTF_OR_RETURN(*str, *size, "# StopWatch %s total/cumulative duration %f Samples: %d\n",
Nicolas Catania39c016f2009-05-18 16:08:12 -0700122 mName, mDuration, mNum);
123 printThroughput(str, size);
124 printAverageMinMax(str, size);
125
126 if (printRaw)
127 {
128 // print comment header and summary values.
129
Xia Wangb0ba9852009-11-19 16:28:25 -0800130 SNPRINTF_OR_RETURN(*str, *size, "# Name Iterations Duration Min MinIdx Max MaxIdx SizeKbytes\n");
Nicolas Catania39c016f2009-05-18 16:08:12 -0700131 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.
149void 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.
165void StopWatch::processSamples()
166{
167 if (kVerbose) fprintf(stderr, "processing samples\n");
Xia Wangb0ba9852009-11-19 16:28:25 -0800168 size_t n = mDataLen / 2;
169 mDeltas= new double[n];
Nicolas Catania39c016f2009-05-18 16:08:12 -0700170 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
Xia Wangb0ba9852009-11-19 16:28:25 -0800178 for (size_t i = 0; i < n; ++i)
Nicolas Catania39c016f2009-05-18 16:08:12 -0700179 {
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 }
Xia Wangb0ba9852009-11-19 16:28:25 -0800199 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);
Nicolas Catania39c016f2009-05-18 16:08:12 -0700206}
207
Xia Wangb0ba9852009-11-19 16:28:25 -0800208
Nicolas Catania39c016f2009-05-18 16:08:12 -0700209double 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.
217void 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);
Xia Wangb0ba9852009-11-19 16:28:25 -0800222 SNPRINTF_OR_RETURN(*str, *size, "# Standard deviation %s duration %f \n", mName, mDeviation);
Nicolas Catania39c016f2009-05-18 16:08:12 -0700223 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
228void 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