Home | History | Annotate | Download | only in sdcard
      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 
     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 
     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 
     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 
     92 void StopWatch::stop()
     93 {
     94     checkCapacity();
     95     clock_gettime(CLOCK_MONOTONIC, &mData[mDataLen].mTime);
     96     mData[mDataLen].mIsStart = false;
     97     ++mDataLen;
     98 }
     99 
    100 void StopWatch::setPrintRawMode(bool raw)
    101 {
    102     printRaw = raw;
    103 }
    104 
    105 
    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.
    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.
    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 
    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.
    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 
    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